1
1
module http_client
2
- use iso_c_binding
3
- use curl
4
- use stdlib_string_type
5
- use fhash, only: key = > fhash_key
2
+ use iso_c_binding, only: c_associated, c_f_pointer, c_funloc, c_loc, &
3
+ c_null_char, c_null_ptr, c_ptr, c_size_t
4
+ use curl, only: c_f_str_ptr, curl_easy_cleanup, curl_easy_getinfo, &
5
+ curl_easy_init, curl_easy_perform, curl_easy_setopt, &
6
+ curl_easy_strerror, curl_slist_append, CURLE_OK, &
7
+ CURLINFO_RESPONSE_CODE, CURLOPT_CUSTOMREQUEST, CURLOPT_HEADERDATA, &
8
+ CURLOPT_HEADERFUNCTION, CURLOPT_HTTPHEADER, CURLOPT_URL, &
9
+ CURLOPT_WRITEDATA, CURLOPT_WRITEFUNCTION
10
+ use stdlib_optval, only: optval
11
+ use stdlib_string_type, only: string_type, to_lower, operator (==)
6
12
use http_request, only: request_type
7
13
use http_response, only: response_type
8
14
use http_header, only : header_type
@@ -32,42 +38,35 @@ module http_client
32
38
function new_request (url , method , header ) result(response)
33
39
character (len=* ), intent (in ) :: url
34
40
integer , intent (in ), optional :: method
35
- type (header_type), intent (inout ), optional :: header
36
- type (header_type) :: default_header
41
+ type (header_type), intent (in ), optional :: header(:)
37
42
type (request_type) :: request
38
43
type (response_type) :: response
39
44
type (client_type) :: client
40
45
41
- ! setting default HTTP method
42
- if (present (method)) then
43
- request% method = method
44
- else
45
- request% method = 1
46
- end if
46
+ ! Set default HTTP method.
47
+ request% method = optval(method, 1 )
47
48
48
- ! setting defautl request headers
49
+ ! Set default request headers.
50
+ request% header = [header_type(' user-agent' , ' fortran-http/1.0.0' )]
49
51
if (present (header)) then
50
- call set_default_headers(header)
51
- request% header = header
52
- else
53
- call set_default_headers(default_header)
54
- request% header = default_header
52
+ request% header = [header, request% header]
55
53
end if
56
- ! populate the request header_key array
57
- call request% header% set_header_key()
54
+
58
55
! setting request url
59
56
request% url = url
57
+
60
58
client = client_type(request= request)
61
- response = client% client_get_response()
62
59
60
+ ! Populates the response
61
+ response = client% client_get_response()
63
62
end function new_request
63
+
64
64
! Constructor for client_type type.
65
65
function new_client (request ) result(client)
66
66
type (request_type), intent (in ) :: request
67
67
type (client_type) :: client
68
68
69
69
client% request = request
70
-
71
70
end function new_client
72
71
73
72
function client_get_response (this ) result(response)
@@ -79,11 +78,10 @@ function client_get_response(this) result(response)
79
78
curl_ptr = c_null_ptr
80
79
header_list_ptr = c_null_ptr
81
80
82
- ! logic for populating response using fortran-curl
83
81
response% url = this% request% url
84
82
85
83
! prepare headers for curl
86
- call prepare_request_header_ptr(header_list_ptr, this% request)
84
+ call prepare_request_header_ptr(header_list_ptr, this% request% header )
87
85
88
86
curl_ptr = curl_easy_init()
89
87
@@ -94,20 +92,28 @@ & function failed. This can occur due to insufficient memory available in the sy
94
92
& Additionally, if libcurl is not installed or configured properly on the system"
95
93
return
96
94
end if
95
+
97
96
! setting request URL
98
97
rc = curl_easy_setopt(curl_ptr, CURLOPT_URL, this% request% url // c_null_char)
98
+
99
99
! setting request method
100
100
rc = client_set_method(curl_ptr, this% request% method, response)
101
+
101
102
! setting request header
102
103
rc = curl_easy_setopt(curl_ptr, CURLOPT_HTTPHEADER, header_list_ptr);
104
+
103
105
! setting callback for writing received data
104
106
rc = curl_easy_setopt(curl_ptr, CURLOPT_WRITEFUNCTION, c_funloc(client_response_callback))
107
+
105
108
! setting response content pointer to write callback
106
109
rc = curl_easy_setopt(curl_ptr, CURLOPT_WRITEDATA, c_loc(response))
110
+
107
111
! setting callback for writing received headers
108
112
rc = curl_easy_setopt(curl_ptr, CURLOPT_HEADERFUNCTION, c_funloc(client_header_callback))
113
+
109
114
! setting response header pointer to write callback
110
115
rc = curl_easy_setopt(curl_ptr, CURLOPT_HEADERDATA, c_loc(response))
116
+
111
117
! Send request.
112
118
rc = curl_easy_perform(curl_ptr)
113
119
@@ -119,35 +125,24 @@ & function failed. This can occur due to insufficient memory available in the sy
119
125
! setting response status_code
120
126
rc = curl_easy_getinfo(curl_ptr, CURLINFO_RESPONSE_CODE, response% status_code)
121
127
122
- ! populate the response header_key array
123
- call response% header% set_header_key()
124
-
125
128
call curl_easy_cleanup(curl_ptr)
126
129
127
130
end function client_get_response
128
131
129
- subroutine prepare_request_header_ptr (header_list_ptr , request )
130
- class(request_type), intent (in ) :: request
132
+ subroutine prepare_request_header_ptr (header_list_ptr , req_headers )
131
133
type (c_ptr), intent (out ) :: header_list_ptr
132
- type (string_type ), allocatable :: req_headers(:)
134
+ type (header_type ), allocatable , intent ( in ) :: req_headers(:)
133
135
character (:), allocatable :: h_key, h_val, final_header_string
134
136
integer :: i
135
137
136
- req_headers = request% header% keys()
137
138
do i = 1 , size (req_headers)
138
- h_key = char (req_headers(i))
139
- h_val = request% header% value(req_headers(i))
140
-
139
+ h_key = req_headers(i)% key
140
+ h_val = req_headers(i)% value
141
141
final_header_string = h_key // ' :' // h_val // c_null_char
142
142
header_list_ptr = curl_slist_append(header_list_ptr, final_header_string)
143
143
end do
144
144
end subroutine prepare_request_header_ptr
145
145
146
- subroutine set_default_headers (header )
147
- type (header_type), intent (inout ) :: header
148
- call header% set(' User-Agent' , ' fortran-http/1.0.0' )
149
- end subroutine set_default_headers
150
-
151
146
function client_set_method (curl_ptr , method , response ) result(status)
152
147
type (c_ptr), intent (out ) :: curl_ptr
153
148
integer , intent (in ) :: method
@@ -203,6 +198,7 @@ function client_response_callback(ptr, size, nmemb, client_data) bind(c)
203
198
response% content = response% content // buf
204
199
deallocate (buf)
205
200
response% content_length = response% content_length + nmemb
201
+
206
202
! Return number of received bytes.
207
203
client_response_callback = nmemb
208
204
@@ -230,20 +226,23 @@ function client_header_callback(ptr, size, nmemb, client_data) bind(c)
230
226
! Convert C pointer to Fortran allocatable character.
231
227
call c_f_str_ptr(ptr, buf, nmemb)
232
228
if (.not. allocated (buf)) return
229
+
233
230
! Parsing Header, and storing in hashmap
234
231
i = index (buf, ' :' )
235
232
if (i /= 0 .and. len (buf) > 2 ) then
236
233
h_key = trim (buf(:i-1 ))
237
234
h_value = buf(i+2 : )
238
235
h_value = h_value( : len (h_value)- 2 )
239
236
if (len (h_value) > 0 .and. len (h_key) > 0 ) then
240
- call response% header% set(h_key, h_value)
237
+ call response% append_header(h_key, h_value)
238
+ ! response%header = [response%header, header_type(h_key, h_value)]
241
239
end if
242
240
end if
243
241
deallocate (buf)
242
+
244
243
! Return number of received bytes.
245
244
client_header_callback = nmemb
246
245
247
246
end function client_header_callback
248
-
247
+
249
248
end module http_client
0 commit comments