@@ -3,6 +3,7 @@ open Bot_info
3
3
open Cohttp
4
4
open Cohttp_lwt_unix
5
5
open Lwt
6
+ open Zip
6
7
7
8
let f = Printf. sprintf
8
9
@@ -43,6 +44,30 @@ let handle_json action body =
43
44
| Yojson.Basic.Util. Type_error (err , _ ) ->
44
45
Error (f " Json type error: %s\n " err)
45
46
47
+ let handle_zip action body =
48
+ let open Lwt_result.Infix in
49
+ Lwt_io. with_temp_file (fun (tmp_name , tmp_channel ) ->
50
+ let open Lwt.Infix in
51
+ Lwt_io. write tmp_channel body
52
+ >> = fun () ->
53
+ Lwt_io. close tmp_channel
54
+ >> = Lwt_preemptive. detach (fun () ->
55
+ try
56
+ let zip_entries =
57
+ let zf = Zip. open_in tmp_name in
58
+ let entries =
59
+ Zip. entries zf
60
+ |> List. filter ~f: (fun entry -> not entry.is_directory)
61
+ |> List. map ~f: (fun entry ->
62
+ (entry, Zip. read_entry zf entry) )
63
+ in
64
+ Zip. close_in zf ; entries
65
+ in
66
+ Ok zip_entries
67
+ with Zip. Error (zip_name , entry_name , message ) ->
68
+ Error (f " Zip.Error(%s, %s, %s)" zip_name entry_name message) ) )
69
+ > |= action
70
+
46
71
(* GitHub specific *)
47
72
48
73
let project_api_preview_header =
@@ -51,14 +76,64 @@ let project_api_preview_header =
51
76
let app_api_preview_header =
52
77
[(" Accept" , " application/vnd.github.machine-man-preview+json" )]
53
78
79
+ let api_json_header = [(" Accept" , " application/vnd.github+json" )]
80
+
54
81
let github_header bot_info =
55
82
[(" Authorization" , " bearer " ^ github_token bot_info)]
56
83
57
- let generic_get ~bot_info relative_uri ?(header_list = [] ) json_handler =
58
- let uri = " https://api.github.com/" ^ relative_uri |> Uri. of_string in
59
- let headers =
60
- headers (header_list @ github_header bot_info) bot_info.github_name
61
- in
84
+ let headers_of_list = headers
85
+
86
+ (* when following a redirect from GitHub to Azure, passing along the
87
+ Authorization header results in 403 Forbidden. So we strip the
88
+ headers when we recurse by default. *)
89
+ let rec client_get ?(follow_redirects = true )
90
+ ?(include_headers_in_redirects = false ) ~user_agent ~headers uri =
62
91
Client. get ~headers uri
63
- >> = (fun (_response , body ) -> Cohttp_lwt.Body. to_string body)
64
- > |= handle_json json_handler
92
+ >> = fun (resp , body ) ->
93
+ match Response. status resp with
94
+ | `OK ->
95
+ Lwt. return_ok body
96
+ | `Moved_permanently
97
+ | `Found
98
+ | `See_other
99
+ | `Temporary_redirect
100
+ | `Permanent_redirect
101
+ when follow_redirects -> (
102
+ let headers =
103
+ if include_headers_in_redirects then headers
104
+ else headers_of_list [] user_agent
105
+ in
106
+ match Header. get_location (Response. headers resp) with
107
+ | Some new_uri ->
108
+ Lwt_io. printlf " Following redirect to %s" (Uri. to_string new_uri)
109
+ >> = fun () ->
110
+ client_get ~follow_redirects ~include_headers_in_redirects ~headers
111
+ ~user_agent new_uri
112
+ | None ->
113
+ let msg =
114
+ f " Redirected from %s, but no Location header found"
115
+ (Uri. to_string uri)
116
+ in
117
+ Lwt. return_error msg )
118
+ | status_code ->
119
+ let msg =
120
+ f " HTTP request to %s failed with status code: %s" (Uri. to_string uri)
121
+ (Code. string_of_status status_code)
122
+ in
123
+ Lwt. return_error msg
124
+
125
+ let generic_get ~bot_info relative_uri ?(header_list = [] ) handler =
126
+ let open Lwt_result.Infix in
127
+ let uri = " https://api.github.com/" ^ relative_uri |> Uri. of_string in
128
+ let user_agent = bot_info.github_name in
129
+ let headers = headers (header_list @ github_header bot_info) user_agent in
130
+ client_get ~headers ~user_agent uri
131
+ >> = (fun body -> Cohttp_lwt.Body. to_string body |> Lwt_result. ok)
132
+ >> = handler
133
+
134
+ let generic_get_json ~bot_info relative_uri ?(header_list = [] ) json_handler =
135
+ generic_get ~bot_info relative_uri ~header_list (fun body ->
136
+ body |> handle_json json_handler |> Lwt. return )
137
+
138
+ let generic_get_zip ~bot_info relative_uri ?(header_list = [] ) zip_handler =
139
+ generic_get ~bot_info relative_uri ~header_list (handle_zip zip_handler)
0 commit comments