diff options
Diffstat (limited to 'src/examples/mhd2spdy_http.c')
-rw-r--r-- | src/examples/mhd2spdy_http.c | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/src/examples/mhd2spdy_http.c b/src/examples/mhd2spdy_http.c new file mode 100644 index 00000000..5f788524 --- /dev/null +++ b/src/examples/mhd2spdy_http.c | |||
@@ -0,0 +1,450 @@ | |||
1 | /* | ||
2 | Copyright (C) 2013 Andrey Uzunov | ||
3 | |||
4 | This program is free software: you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation, either version 3 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | /** | ||
19 | * @file structures.h | ||
20 | * @author Andrey Uzunov | ||
21 | */ | ||
22 | |||
23 | #include "mhd2spdy_structures.h" | ||
24 | #include "mhd2spdy_http.h" | ||
25 | #include "mhd2spdy_spdy.h" | ||
26 | |||
27 | |||
28 | void * http_log_cb(void * cls, const char * uri) | ||
29 | { | ||
30 | struct HTTP_URI * http_uri; | ||
31 | |||
32 | PRINT_INFO2("log uri '%s'\n", uri); | ||
33 | |||
34 | if(NULL == (http_uri = au_malloc(sizeof(struct HTTP_URI )))) | ||
35 | DIE("no memory"); | ||
36 | //memset(http_uri, 0 , sizeof(struct HTTP_URI)); | ||
37 | http_uri->uri = strdup(uri); | ||
38 | return http_uri; | ||
39 | } | ||
40 | |||
41 | |||
42 | /* | ||
43 | static int | ||
44 | http_query_iterate_cb(void *cls, | ||
45 | enum MHD_ValueKind kind, | ||
46 | const char *name, const char *value) | ||
47 | { | ||
48 | |||
49 | }*/ | ||
50 | |||
51 | |||
52 | static int | ||
53 | http_iterate_cb(void *cls, | ||
54 | enum MHD_ValueKind kind, | ||
55 | const char *name, const char *value) | ||
56 | { | ||
57 | static char * const forbidden[] = {"Transfer-Encoding", | ||
58 | "Proxy-Connection", | ||
59 | "Keep-Alive", | ||
60 | "Connection"}; | ||
61 | static int forbidden_size = 4; | ||
62 | int i; | ||
63 | struct SPDY_Headers *spdy_headers = (struct SPDY_Headers *)cls; | ||
64 | |||
65 | if(0 == strcasecmp(name, "Host")) | ||
66 | spdy_headers->nv[9] = (char *)value; | ||
67 | else | ||
68 | { | ||
69 | for(i=0; i<forbidden_size; ++i) | ||
70 | if(0 == strcasecmp(forbidden[i], name)) | ||
71 | return MHD_YES; | ||
72 | spdy_headers->nv[spdy_headers->cnt++] = (char *)name; | ||
73 | spdy_headers->nv[spdy_headers->cnt++] = (char *)value; | ||
74 | } | ||
75 | |||
76 | return MHD_YES; | ||
77 | } | ||
78 | |||
79 | |||
80 | static ssize_t | ||
81 | http_response_callback (void *cls, | ||
82 | uint64_t pos, | ||
83 | char *buffer, | ||
84 | size_t max) | ||
85 | { | ||
86 | int ret; | ||
87 | struct Proxy *proxy = (struct Proxy *)cls; | ||
88 | void *newbody; | ||
89 | const union MHD_ConnectionInfo *info; | ||
90 | int val = 1; | ||
91 | |||
92 | //max=16; | ||
93 | |||
94 | //PRINT_INFO2("response_callback, pos: %i, max is %i, len is %i",pos,max,proxy->length); | ||
95 | |||
96 | //assert(0 != proxy->length); | ||
97 | |||
98 | //if(MHD_CONTENT_READER_END_OF_STREAM == proxy->length) | ||
99 | // return MHD_CONTENT_READER_END_OF_STREAM; | ||
100 | |||
101 | PRINT_INFO2("http_response_callback for %s", proxy->url); | ||
102 | |||
103 | if(0 == proxy->http_body_size &&( proxy->done || !proxy->spdy_active)){ | ||
104 | PRINT_INFO("sent end of stream"); | ||
105 | return MHD_CONTENT_READER_END_OF_STREAM; | ||
106 | } | ||
107 | |||
108 | //*more = true; | ||
109 | if(!proxy->http_body_size)//nothing to write now | ||
110 | { | ||
111 | //flush data | ||
112 | info = MHD_get_connection_info (proxy->http_connection, | ||
113 | MHD_CONNECTION_INFO_CONNECTION_FD); | ||
114 | ret = setsockopt(info->connect_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)); | ||
115 | if(ret == -1) { | ||
116 | DIE("setsockopt"); | ||
117 | } | ||
118 | |||
119 | PRINT_INFO("FLUSH data"); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | if(max >= proxy->http_body_size) | ||
124 | { | ||
125 | ret = proxy->http_body_size; | ||
126 | newbody = NULL; | ||
127 | } | ||
128 | else | ||
129 | { | ||
130 | ret = max; | ||
131 | if(NULL == (newbody = au_malloc(proxy->http_body_size - max))) | ||
132 | { | ||
133 | PRINT_INFO("no memory"); | ||
134 | return -2; | ||
135 | } | ||
136 | memcpy(newbody, proxy->http_body + max, proxy->http_body_size - max); | ||
137 | } | ||
138 | memcpy(buffer, proxy->http_body, ret); | ||
139 | free(proxy->http_body); | ||
140 | proxy->http_body = newbody; | ||
141 | proxy->http_body_size -= ret; | ||
142 | |||
143 | if(proxy->length >= 0) | ||
144 | { | ||
145 | proxy->length -= ret; | ||
146 | //printf("pr len %i", proxy->length); | ||
147 | /*if(proxy->length <= 0) | ||
148 | { | ||
149 | // *more = false; | ||
150 | //last frame | ||
151 | proxy->length = MHD_CONTENT_READER_END_OF_STREAM; | ||
152 | }*/ | ||
153 | } | ||
154 | |||
155 | PRINT_INFO2("response_callback, size: %i",ret); | ||
156 | |||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | |||
161 | static void | ||
162 | http_response_done_callback(void *cls) | ||
163 | { | ||
164 | struct Proxy *proxy = (struct Proxy *)cls; | ||
165 | |||
166 | PRINT_INFO2("http_response_done_callback for %s", proxy->url); | ||
167 | //int ret; | ||
168 | |||
169 | //printf("response_done_callback\n"); | ||
170 | |||
171 | //printf("answer for %s was sent\n", (char *)cls); | ||
172 | |||
173 | /*if(SPDY_RESPONSE_RESULT_SUCCESS != status) | ||
174 | { | ||
175 | printf("answer was NOT sent, %i\n",status); | ||
176 | }*/ | ||
177 | /*if(CURLM_OK != (ret = curl_multi_remove_handle(multi_handle, proxy->curl_handle))) | ||
178 | { | ||
179 | PRINT_INFO2("curl_multi_remove_handle failed (%i)", ret); | ||
180 | } | ||
181 | curl_slist_free_all(proxy->curl_headers); | ||
182 | curl_easy_cleanup(proxy->curl_handle); | ||
183 | */ | ||
184 | //SPDY_destroy_request(request); | ||
185 | //SPDY_destroy_response(response); | ||
186 | MHD_destroy_response (proxy->http_response); | ||
187 | //if(!strcmp("/close",proxy->path)) run = 0; | ||
188 | //free(proxy->path); | ||
189 | if(proxy->spdy_active) | ||
190 | proxy->http_active = false; | ||
191 | else | ||
192 | free_proxy(proxy); | ||
193 | |||
194 | --glob_opt.responses_pending; | ||
195 | } | ||
196 | |||
197 | int | ||
198 | http_cb_request (void *cls, | ||
199 | struct MHD_Connection *connection, | ||
200 | const char *url, | ||
201 | const char *method, | ||
202 | const char *version, | ||
203 | const char *upload_data, | ||
204 | size_t *upload_data_size, | ||
205 | void **ptr) | ||
206 | { | ||
207 | //struct MHD_Response *response; | ||
208 | int ret; | ||
209 | struct Proxy *proxy; | ||
210 | //struct URI *spdy_uri; | ||
211 | //char **nv; | ||
212 | //int num_headers; | ||
213 | struct SPDY_Headers spdy_headers; | ||
214 | |||
215 | //PRINT_INFO2("request cb %i; %s", *ptr,url); | ||
216 | |||
217 | if (NULL == *ptr) | ||
218 | DIE("ptr is null"); | ||
219 | struct HTTP_URI *http_uri = (struct HTTP_URI *)*ptr; | ||
220 | |||
221 | if(NULL == http_uri->proxy) | ||
222 | { | ||
223 | if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) | ||
224 | { | ||
225 | free(http_uri->uri); | ||
226 | free(http_uri); | ||
227 | PRINT_INFO2("unexpected method %s", method); | ||
228 | return MHD_NO; /* unexpected method */ | ||
229 | } | ||
230 | |||
231 | if(NULL == (proxy = au_malloc(sizeof(struct Proxy)))) | ||
232 | { | ||
233 | PRINT_INFO("No memory"); | ||
234 | return MHD_NO; | ||
235 | } | ||
236 | |||
237 | ++glob_opt.responses_pending; | ||
238 | //memset(proxy, 0, sizeof(struct Proxy)); | ||
239 | proxy->id = rand(); | ||
240 | proxy->http_active = true; | ||
241 | //PRINT_INFO2("proxy obj with id %i created (%i)", proxy->id, proxy); | ||
242 | proxy->http_connection = connection; | ||
243 | http_uri->proxy = proxy; | ||
244 | return MHD_YES; | ||
245 | } | ||
246 | |||
247 | proxy = http_uri->proxy; | ||
248 | //*ptr = NULL; /* reset when done */ | ||
249 | |||
250 | if(proxy->spdy_active) | ||
251 | { | ||
252 | //already handled | ||
253 | PRINT_INFO("unnecessary call to http_cb_request"); | ||
254 | return MHD_YES; | ||
255 | } | ||
256 | |||
257 | PRINT_INFO2("received request for '%s %s %s'\n", method, http_uri->uri, version); | ||
258 | /* | ||
259 | proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, | ||
260 | 8096, | ||
261 | &http_response_callback, | ||
262 | proxy, | ||
263 | &http_response_done_callback); | ||
264 | |||
265 | if (proxy->http_response == NULL) | ||
266 | DIE("no response"); | ||
267 | */ | ||
268 | |||
269 | proxy->url = http_uri->uri; | ||
270 | //if(NULL == (proxy->url = strdup(http_uri->uri))) | ||
271 | // DIE("no memory"); | ||
272 | |||
273 | //TODO HTTP headers | ||
274 | /*MHD_get_connection_values (connection, | ||
275 | MHD_HEADER_KIND, | ||
276 | &http_iterate_cb, | ||
277 | proxy); | ||
278 | */ | ||
279 | //proxy->url = strdup(url); | ||
280 | //if(NULL == (spdy_uri = au_malloc(sizeof(struct URI)))) | ||
281 | // DIE("no memory"); | ||
282 | |||
283 | ret = parse_uri(&glob_opt.uri_preg, proxy->url, &proxy->uri); | ||
284 | if(ret != 0) | ||
285 | DIE("parse_uri failed"); | ||
286 | //proxy->uri = spdy_uri; | ||
287 | proxy->http_uri = http_uri; | ||
288 | proxy->spdy_active = true; | ||
289 | |||
290 | //proxy->spdy_request = au_malloc(sizeof(struct SPDY_Request)); | ||
291 | //if(NULL == proxy->spdy_request) | ||
292 | // DIE("no memory"); | ||
293 | //memset(proxy->spdy_request,0,sizeof(struct SPDY_Request)); | ||
294 | //spdy_request_init(proxy->spdy_request, &spdy_uri); | ||
295 | //spdy_submit_request(spdy_connection, proxy); | ||
296 | |||
297 | spdy_headers.num = MHD_get_connection_values (connection, | ||
298 | MHD_HEADER_KIND, | ||
299 | NULL, | ||
300 | NULL); | ||
301 | if(NULL == (spdy_headers.nv = au_malloc(((spdy_headers.num + 5) * 2 + 1) * sizeof(char *)))) | ||
302 | DIE("no memory"); | ||
303 | spdy_headers.nv[0] = ":method"; spdy_headers.nv[1] = "GET"; | ||
304 | spdy_headers.nv[2] = ":path"; spdy_headers.nv[3] = proxy->uri->path_and_more; | ||
305 | spdy_headers.nv[4] = ":version"; spdy_headers.nv[5] = (char *)version; | ||
306 | spdy_headers.nv[6] = ":scheme"; spdy_headers.nv[7] = proxy->uri->scheme; | ||
307 | spdy_headers.nv[8] = ":host"; spdy_headers.nv[9] = NULL; | ||
308 | //nv[14] = NULL; | ||
309 | spdy_headers.cnt = 10; | ||
310 | MHD_get_connection_values (connection, | ||
311 | MHD_HEADER_KIND, | ||
312 | &http_iterate_cb, | ||
313 | &spdy_headers); | ||
314 | |||
315 | spdy_headers.nv[spdy_headers.cnt] = NULL; | ||
316 | if(NULL == spdy_headers.nv[9]) | ||
317 | spdy_headers.nv[9] = proxy->uri->host_and_port; | ||
318 | |||
319 | /*int i; | ||
320 | for(i=0; i<spdy_headers.cnt; i+=2) | ||
321 | printf("%s: %s\n", spdy_headers.nv[i], spdy_headers.nv[i+1]); | ||
322 | */ | ||
323 | if(0 != spdy_request(spdy_headers.nv, proxy)) | ||
324 | { | ||
325 | //--glob_opt.responses_pending; | ||
326 | free(spdy_headers.nv); | ||
327 | //MHD_destroy_response (proxy->http_response); | ||
328 | free_proxy(proxy);//TODO call it here or in done_callback | ||
329 | |||
330 | return MHD_NO; | ||
331 | } | ||
332 | free(spdy_headers.nv); | ||
333 | |||
334 | proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, | ||
335 | 4096, | ||
336 | &http_response_callback, | ||
337 | proxy, | ||
338 | &http_response_done_callback); | ||
339 | |||
340 | if (proxy->http_response == NULL) | ||
341 | DIE("no response"); | ||
342 | |||
343 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
344 | "Proxy-Connection", "keep-alive")) | ||
345 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
346 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
347 | "Connection", "Keep-Alive")) | ||
348 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
349 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
350 | "Keep-Alive", "timeout=5, max=100")) | ||
351 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
352 | |||
353 | /* | ||
354 | const union MHD_ConnectionInfo *info; | ||
355 | info = MHD_get_connection_info (connection, | ||
356 | MHD_CONNECTION_INFO_CONNECTION_FD); | ||
357 | int val = 1; | ||
358 | int rv; | ||
359 | rv = setsockopt(info->connect_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)); | ||
360 | if(rv == -1) { | ||
361 | DIE("setsockopt"); | ||
362 | }*/ | ||
363 | return MHD_YES; | ||
364 | } | ||
365 | |||
366 | void | ||
367 | http_create_response(struct Proxy* proxy, char **nv) | ||
368 | { | ||
369 | size_t i; | ||
370 | //uint64_t response_size=MHD_SIZE_UNKNOWN; | ||
371 | |||
372 | /*for(i = 0; nv[i]; i += 2) { | ||
373 | if(0 == strcmp("content-length", nv[i])) | ||
374 | { | ||
375 | response_size = atoi(nv[i+1]); | ||
376 | break; | ||
377 | } | ||
378 | }*/ | ||
379 | /* | ||
380 | proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, | ||
381 | 4096, | ||
382 | &http_response_callback, | ||
383 | proxy, | ||
384 | &http_response_done_callback); | ||
385 | |||
386 | if (proxy->http_response == NULL) | ||
387 | DIE("no response"); | ||
388 | |||
389 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
390 | "Proxy-Connection", "keep-alive")) | ||
391 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
392 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
393 | "Connection", "Keep-Alive")) | ||
394 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
395 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
396 | "Keep-Alive", "timeout=5, max=100")) | ||
397 | PRINT_INFO("SPDY_name_value_add failed: "); | ||
398 | */ | ||
399 | for(i = 0; nv[i]; i += 2) { | ||
400 | //printf(" %s: %s\n", nv[i], nv[i+1]); | ||
401 | //int j; | ||
402 | |||
403 | if(0 == strcmp(":status", nv[i])) | ||
404 | { | ||
405 | //raise(SIGINT); | ||
406 | //proxy->status_msg = nv[i+1]; | ||
407 | char tmp[4]; | ||
408 | memcpy(&tmp,nv[i+1],3); | ||
409 | tmp[3]=0; | ||
410 | proxy->status = atoi(tmp); | ||
411 | continue; | ||
412 | } | ||
413 | else if(0 == strcmp(":version", nv[i])) | ||
414 | { | ||
415 | proxy->version = nv[i+1]; | ||
416 | continue; | ||
417 | } | ||
418 | else if(0 == strcmp("content-length", nv[i])) | ||
419 | { | ||
420 | //proxy->length = atoi(nv[i+1]); | ||
421 | //response_size = atoi(nv[i+1]); | ||
422 | continue; | ||
423 | } | ||
424 | |||
425 | //for(j=0; j<strlen(nv[i]) && ':'==nv[i][j]; ++j); | ||
426 | |||
427 | char *header = *(nv+i); | ||
428 | //header[0] = toupper(header[0]); | ||
429 | if(MHD_NO == MHD_add_response_header (proxy->http_response, | ||
430 | header, nv[i+1])) | ||
431 | { | ||
432 | PRINT_INFO2("SPDY_name_value_add failed: '%s' '%s'", header, nv[i+1]); | ||
433 | //abort(); | ||
434 | } | ||
435 | PRINT_INFO2("adding '%s: %s'",header, nv[i+1]); | ||
436 | } | ||
437 | |||
438 | //PRINT_INFO2("%i", MHD_get_response_headers(proxy->http_response, NULL, NULL)); | ||
439 | //PRINT_INFO2("state before %i", proxy->http_connection->state); | ||
440 | //PRINT_INFO2("loop before %i", proxy->http_connection->event_loop_info); | ||
441 | if(MHD_NO == MHD_queue_response (proxy->http_connection, proxy->status, proxy->http_response)){ | ||
442 | PRINT_INFO("No queue"); | ||
443 | abort(); | ||
444 | } | ||
445 | //PRINT_INFO2("state after %i", proxy->http_connection->state); | ||
446 | //PRINT_INFO2("loop after %i", proxy->http_connection->event_loop_info); | ||
447 | //MHD_destroy_response (proxy->http_response); | ||
448 | //PRINT_INFO2("state after %i", proxy->http_connection->state); | ||
449 | //PRINT_INFO2("loop after %i", proxy->http_connection->event_loop_info); | ||
450 | } | ||