1+ module http_server
2+ use iso_c_binding
3+ use curl
4+ use http_request, only : request_type
5+ use http_response, only : response_type
6+
7+ implicit none
8+
9+ ! http_server Type
10+ type :: client_type
11+ type (request_type) :: request
12+ type (c_ptr) :: curl_ptr
13+ contains
14+ procedure :: client_get_response
15+ procedure :: client_set_method
16+ end type client_type
17+
18+ interface client_type
19+ module procedure new_client
20+ end interface client_type
21+
22+ interface request
23+ module procedure new_request
24+ end interface request
25+
26+ public :: request
27+
28+
29+ contains
30+ ! Constructor for request_type type.
31+ function new_request (url , method ) result(response)
32+ character (len=* ) :: url
33+ integer , optional :: method
34+ type (request_type) :: request
35+ type (response_type) :: response
36+ type (client_type) :: client
37+
38+ if (present (method)) then
39+ request% method = method
40+ else
41+ request% method = 1
42+ end if
43+ request% url = url
44+ client = client_type(request= request)
45+ response = client% client_get_response()
46+
47+ end function new_request
48+ ! Constructor for client_type type.
49+ function new_client (request ) result(client)
50+ type (client_type) :: client
51+ type (request_type) :: request
52+
53+ client% request = request
54+ end function new_client
55+
56+ function client_get_response (this ) result(response)
57+ class(client_type) :: this
58+ type (response_type), target :: response
59+ integer :: rc
60+ ! logic for populating response using fortran-curl
61+ response% url = this% request% url
62+ ! response%method = this%request%method
63+
64+ this% curl_ptr = curl_easy_init()
65+
66+ if (.not. c_associated(this% curl_ptr)) then
67+ stop ' Error: curl_easy_init() failed'
68+ end if
69+ ! setting request URL
70+ rc = curl_easy_setopt(this% curl_ptr, CURLOPT_URL, this% request% url // c_null_char)
71+ ! setting request method
72+ rc = this% client_set_method(response)
73+ ! setting callback for writing received data
74+ rc = curl_easy_setopt(this% curl_ptr, CURLOPT_WRITEFUNCTION, c_funloc(client_response_callback))
75+ ! setting response pointer to write callback
76+ rc = curl_easy_setopt(this% curl_ptr, CURLOPT_WRITEDATA, c_loc(response))
77+
78+ ! Send request.
79+ rc = curl_easy_perform(this% curl_ptr)
80+
81+ if (rc /= CURLE_OK) then
82+ print ' (a)' , ' Error: curl_easy_perform() failed'
83+ stop
84+ end if
85+ ! setting response status_code
86+ rc = curl_easy_getinfo(this% curl_ptr, CURLINFO_RESPONSE_CODE, response% status_code)
87+ call curl_easy_cleanup(this% curl_ptr)
88+
89+ end function client_get_response
90+
91+ function client_set_method (this , response ) result(status)
92+ class(client_type) :: this
93+ type (response_type), intent (out ) :: response
94+ integer :: status
95+
96+ select case (this% request% method)
97+ case (1 )
98+ status = curl_easy_setopt(this% curl_ptr, CURLOPT_CUSTOMREQUEST, ' GET' // c_null_char)
99+ response% method = ' GET'
100+ case (2 )
101+ status = curl_easy_setopt(this% curl_ptr, CURLOPT_CUSTOMREQUEST, ' HEAD' // c_null_char)
102+ response% method = ' HEAD'
103+ case (3 )
104+ status = curl_easy_setopt(this% curl_ptr, CURLOPT_CUSTOMREQUEST, ' POST' // c_null_char)
105+ response% method = ' POST'
106+ case (4 )
107+ status = curl_easy_setopt(this% curl_ptr, CURLOPT_CUSTOMREQUEST, ' PUT' // c_null_char)
108+ response% method = ' PUT'
109+ case (5 )
110+ status = curl_easy_setopt(this% curl_ptr, CURLOPT_CUSTOMREQUEST, ' DELETE' // c_null_char)
111+ response% method = ' DELETE'
112+ case (6 )
113+ status = curl_easy_setopt(this% curl_ptr, CURLOPT_CUSTOMREQUEST, ' PATCH' // c_null_char)
114+ response% method = ' PATCH'
115+ end select
116+ end function client_set_method
117+
118+ function client_response_callback (ptr , size , nmemb , client_data ) bind(c)
119+ type (c_ptr), intent (in ), value :: ptr
120+ integer (kind= c_size_t), intent (in ), value :: size
121+ integer (kind= c_size_t), intent (in ), value :: nmemb
122+ type (c_ptr), intent (in ), value :: client_data
123+ integer (kind= c_size_t) :: client_response_callback
124+ type (response_type), pointer :: response
125+ character (len= :), allocatable :: buf
126+
127+ client_response_callback = int (0 , kind= c_size_t)
128+
129+ ! Are the passed C pointers associated?
130+ if (.not. c_associated(ptr)) return
131+ if (.not. c_associated(client_data)) return
132+
133+ ! Convert C pointer to Fortran pointer.
134+ call c_f_pointer(client_data, response)
135+ if (.not. allocated (response% content)) response% content = ' '
136+
137+ ! Convert C pointer to Fortran allocatable character.
138+ call c_f_str_ptr(ptr, buf, nmemb)
139+ if (.not. allocated (buf)) return
140+ response% content = response% content // buf
141+ deallocate (buf)
142+ response% content_length = response% content_length + nmemb
143+ ! Return number of received bytes.
144+ client_response_callback = nmemb
145+ end function client_response_callback
146+
147+
148+ end module http_server
0 commit comments