diff options
Diffstat (limited to 'src/spdy2http/proxy.c')
-rw-r--r-- | src/spdy2http/proxy.c | 127 |
1 files changed, 78 insertions, 49 deletions
diff --git a/src/spdy2http/proxy.c b/src/spdy2http/proxy.c index 018896ee..0c303823 100644 --- a/src/spdy2http/proxy.c +++ b/src/spdy2http/proxy.c | |||
@@ -20,9 +20,6 @@ | |||
20 | * @file proxy.c | 20 | * @file proxy.c |
21 | * @brief Translates incoming SPDY requests to http server on localhost. | 21 | * @brief Translates incoming SPDY requests to http server on localhost. |
22 | * Uses libcurl. | 22 | * Uses libcurl. |
23 | * BUGS: | ||
24 | * Now the proxy works only when the HTTP server issues | ||
25 | * "Content-Length" header. Will brake on chunhed response. | ||
26 | * No error handling for curl requests. | 23 | * No error handling for curl requests. |
27 | * @author Andrey Uzunov | 24 | * @author Andrey Uzunov |
28 | */ | 25 | */ |
@@ -86,8 +83,9 @@ struct Proxy | |||
86 | char *status_msg; | 83 | char *status_msg; |
87 | void *http_body; | 84 | void *http_body; |
88 | size_t http_body_size; | 85 | size_t http_body_size; |
89 | ssize_t length; | 86 | //ssize_t length; |
90 | int status; | 87 | int status; |
88 | bool done; | ||
91 | }; | 89 | }; |
92 | 90 | ||
93 | 91 | ||
@@ -102,12 +100,14 @@ response_callback (void *cls, | |||
102 | void *newbody; | 100 | void *newbody; |
103 | 101 | ||
104 | //printf("response_callback\n"); | 102 | //printf("response_callback\n"); |
103 | |||
104 | *more = true; | ||
105 | 105 | ||
106 | assert(0 != proxy->length); | ||
107 | |||
108 | *more = true; | ||
109 | if(!proxy->http_body_size)//nothing to write now | 106 | if(!proxy->http_body_size)//nothing to write now |
107 | { | ||
108 | if(proxy->done) *more = false; | ||
110 | return 0; | 109 | return 0; |
110 | } | ||
111 | 111 | ||
112 | if(max >= proxy->http_body_size) | 112 | if(max >= proxy->http_body_size) |
113 | { | 113 | { |
@@ -129,17 +129,7 @@ response_callback (void *cls, | |||
129 | proxy->http_body = newbody; | 129 | proxy->http_body = newbody; |
130 | proxy->http_body_size -= ret; | 130 | proxy->http_body_size -= ret; |
131 | 131 | ||
132 | if(proxy->length >= 0) | 132 | if(proxy->done && 0 == proxy->http_body_size) *more = false; |
133 | { | ||
134 | proxy->length -= ret; | ||
135 | //printf("pr len %i", proxy->length); | ||
136 | if(proxy->length <= 0) | ||
137 | { | ||
138 | *more = false; | ||
139 | //last frame | ||
140 | proxy->length = 0; | ||
141 | } | ||
142 | } | ||
143 | 133 | ||
144 | return ret; | 134 | return ret; |
145 | } | 135 | } |
@@ -188,11 +178,17 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
188 | char *name; | 178 | char *name; |
189 | char *value; | 179 | char *value; |
190 | char *status; | 180 | char *status; |
191 | const char *const*length; | ||
192 | int i; | 181 | int i; |
193 | int pos; | 182 | int pos; |
183 | int ret; | ||
184 | int num_values; | ||
185 | const char * const * values; | ||
186 | bool abort_it; | ||
194 | 187 | ||
195 | //printf("curl_header_cb\n"); | 188 | //printf("curl_header_cb %s\n", line); |
189 | |||
190 | //trailer | ||
191 | if(NULL != proxy->response) return 0; | ||
196 | 192 | ||
197 | if('\r' == line[0]) | 193 | if('\r' == line[0]) |
198 | { | 194 | { |
@@ -208,12 +204,7 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
208 | PRINT_INFO("no response"); | 204 | PRINT_INFO("no response"); |
209 | abort(); | 205 | abort(); |
210 | } | 206 | } |
211 | if(NULL != (length = SPDY_name_value_lookup(proxy->headers, | 207 | |
212 | SPDY_HTTP_HEADER_CONTENT_LENGTH, | ||
213 | &i))) | ||
214 | proxy->length = atoi(length[0]); | ||
215 | else | ||
216 | proxy->length = -1; | ||
217 | SPDY_name_value_destroy(proxy->headers); | 208 | SPDY_name_value_destroy(proxy->headers); |
218 | free(proxy->status_msg); | 209 | free(proxy->status_msg); |
219 | free(proxy->version); | 210 | free(proxy->version); |
@@ -228,7 +219,6 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
228 | PRINT_INFO("no queue"); | 219 | PRINT_INFO("no queue"); |
229 | abort(); | 220 | abort(); |
230 | } | 221 | } |
231 | //printf("spdy headers queued %i\n"); | ||
232 | 222 | ||
233 | return realsize; | 223 | return realsize; |
234 | } | 224 | } |
@@ -310,10 +300,23 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
310 | PRINT_INFO("no memory"); | 300 | PRINT_INFO("no memory"); |
311 | abort(); | 301 | abort(); |
312 | } | 302 | } |
313 | if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, value)) | 303 | if(SPDY_YES != (ret = SPDY_name_value_add(proxy->headers, name, value))) |
314 | { | 304 | { |
315 | PRINT_INFO("SPDY_name_value_add failed"); | 305 | abort_it=true; |
316 | abort(); | 306 | if(NULL != (values = SPDY_name_value_lookup(proxy->headers, name, &num_values))) |
307 | for(i=0; i<num_values; ++i) | ||
308 | if(0 == strcasecmp(value, values[i])) | ||
309 | { | ||
310 | abort_it=false; | ||
311 | PRINT_INFO2("header appears more than once with same value '%s: %s'", name, value); | ||
312 | break; | ||
313 | } | ||
314 | |||
315 | if(abort_it) | ||
316 | { | ||
317 | PRINT_INFO2("SPDY_name_value_add failed (%i) for '%s'", ret, name); | ||
318 | abort(); | ||
319 | } | ||
317 | } | 320 | } |
318 | free(name); | 321 | free(name); |
319 | free(value); | 322 | free(value); |
@@ -329,7 +332,7 @@ curl_write_cb(void *contents, size_t size, size_t nmemb, void *userp) | |||
329 | struct Proxy *proxy = (struct Proxy *)userp; | 332 | struct Proxy *proxy = (struct Proxy *)userp; |
330 | 333 | ||
331 | //printf("curl_write_cb %i\n", realsize); | 334 | //printf("curl_write_cb %i\n", realsize); |
332 | 335 | ||
333 | if(NULL == proxy->http_body) | 336 | if(NULL == proxy->http_body) |
334 | proxy->http_body = malloc(realsize); | 337 | proxy->http_body = malloc(realsize); |
335 | else | 338 | else |
@@ -351,13 +354,13 @@ int | |||
351 | iterate_cb (void *cls, const char *name, const char * const * value, int num_values) | 354 | iterate_cb (void *cls, const char *name, const char * const * value, int num_values) |
352 | { | 355 | { |
353 | struct Proxy *proxy = (struct Proxy *)cls; | 356 | struct Proxy *proxy = (struct Proxy *)cls; |
354 | struct curl_slist **curl_headers = (&(proxy->curl_headers)); | 357 | struct curl_slist **curl_headers = (&(proxy->curl_headers)); |
355 | char *line; | 358 | char *line; |
356 | int line_len = strlen(name) + 3; //+ ": \0" | 359 | int line_len = strlen(name) + 3; //+ ": \0" |
357 | int i; | 360 | int i; |
358 | 361 | ||
359 | for(i=0; i<num_values; ++i) | 362 | for(i=0; i<num_values; ++i) |
360 | { | 363 | { |
361 | if(i) line_len += 2; //", " | 364 | if(i) line_len += 2; //", " |
362 | line_len += strlen(value[i]); | 365 | line_len += strlen(value[i]); |
363 | } | 366 | } |
@@ -394,14 +397,14 @@ iterate_cb (void *cls, const char *name, const char * const * value, int num_val | |||
394 | 397 | ||
395 | void | 398 | void |
396 | standard_request_handler(void *cls, | 399 | standard_request_handler(void *cls, |
397 | struct SPDY_Request * request, | 400 | struct SPDY_Request * request, |
398 | uint8_t priority, | 401 | uint8_t priority, |
399 | const char *method, | 402 | const char *method, |
400 | const char *path, | 403 | const char *path, |
401 | const char *version, | 404 | const char *version, |
402 | const char *host, | 405 | const char *host, |
403 | const char *scheme, | 406 | const char *scheme, |
404 | struct SPDY_NameValue * headers) | 407 | struct SPDY_NameValue * headers) |
405 | { | 408 | { |
406 | (void)cls; | 409 | (void)cls; |
407 | (void)priority; | 410 | (void)priority; |
@@ -426,6 +429,7 @@ standard_request_handler(void *cls, | |||
426 | abort(); | 429 | abort(); |
427 | } | 430 | } |
428 | 431 | ||
432 | //TODO add https | ||
429 | if(0 == strcmp(http_host, "any")) | 433 | if(0 == strcmp(http_host, "any")) |
430 | ret = asprintf(&url,"%s%s%s","http://", host, path); | 434 | ret = asprintf(&url,"%s%s%s","http://", host, path); |
431 | else | 435 | else |
@@ -460,9 +464,10 @@ standard_request_handler(void *cls, | |||
460 | CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEDATA, proxy); | 464 | CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEDATA, proxy); |
461 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERFUNCTION, curl_header_cb); | 465 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERFUNCTION, curl_header_cb); |
462 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERDATA, proxy); | 466 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HEADERDATA, proxy); |
467 | CURL_SETOPT(proxy->curl_handle, CURLOPT_PRIVATE, proxy); | ||
463 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTPHEADER, proxy->curl_headers); | 468 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTPHEADER, proxy->curl_headers); |
464 | CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); | 469 | CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); |
465 | CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); | 470 | CURL_SETOPT(proxy->curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); |
466 | 471 | ||
467 | if(CURLM_OK != (ret = curl_multi_add_handle(multi_handle, proxy->curl_handle))) | 472 | if(CURLM_OK != (ret = curl_multi_add_handle(multi_handle, proxy->curl_handle))) |
468 | { | 473 | { |
@@ -482,7 +487,7 @@ int | |||
482 | main (int argc, char *const *argv) | 487 | main (int argc, char *const *argv) |
483 | { | 488 | { |
484 | unsigned long long timeoutlong=0; | 489 | unsigned long long timeoutlong=0; |
485 | long curl_timeo = -1; | 490 | long curl_timeo = -1; |
486 | struct timeval timeout; | 491 | struct timeval timeout; |
487 | int ret; | 492 | int ret; |
488 | fd_set rs; | 493 | fd_set rs; |
@@ -493,14 +498,17 @@ main (int argc, char *const *argv) | |||
493 | fd_set curl_es; | 498 | fd_set curl_es; |
494 | int maxfd = -1; | 499 | int maxfd = -1; |
495 | struct SPDY_Daemon *daemon; | 500 | struct SPDY_Daemon *daemon; |
496 | 501 | CURLMsg *msg; | |
497 | //signal(SIGPIPE, SIG_IGN); | 502 | int msgs_left; |
503 | struct Proxy *proxy; | ||
504 | |||
505 | signal(SIGPIPE, SIG_IGN); | ||
498 | 506 | ||
499 | if(argc != 6) | 507 | if(argc != 6) |
500 | { | 508 | { |
501 | printf("Usage: %s cert-file key-file host port http/1.0(yes/no)\n\ | 509 | printf("Usage: %s cert-file key-file host port http/1.0(yes/no)\n\ |
502 | \n\ | 510 | \n\ |
503 | Example for forward proxy (':host' header is used to know which HTTP server to connect):\n\ | 511 | Example for transparent proxy (':host' header is used to know which HTTP server to connect):\n\ |
504 | %s cert.pem key.pem any 8080 no\n", argv[0], argv[0]); | 512 | %s cert.pem key.pem any 8080 no\n", argv[0], argv[0]); |
505 | return 1; | 513 | return 1; |
506 | } | 514 | } |
@@ -623,8 +631,29 @@ Example for forward proxy (':host' header is used to know which HTTP server to c | |||
623 | } | 631 | } |
624 | break; | 632 | break; |
625 | } | 633 | } |
626 | } | 634 | |
627 | while(run); | 635 | while ((msg = curl_multi_info_read(multi_handle, &msgs_left))) { |
636 | if (msg->msg == CURLMSG_DONE) { | ||
637 | if(CURLE_OK == msg->data.result) | ||
638 | { | ||
639 | if(CURLE_OK != (ret = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &proxy))) | ||
640 | { | ||
641 | PRINT_INFO2("err %i",ret); | ||
642 | abort(); | ||
643 | } | ||
644 | |||
645 | proxy->done = true; | ||
646 | } | ||
647 | else | ||
648 | { | ||
649 | //TODO handle error | ||
650 | PRINT_INFO("bad curl result"); | ||
651 | } | ||
652 | } | ||
653 | else PRINT_INFO("shouldn't happen"); | ||
654 | } | ||
655 | } | ||
656 | while(run); | ||
628 | 657 | ||
629 | curl_multi_cleanup(multi_handle); | 658 | curl_multi_cleanup(multi_handle); |
630 | 659 | ||