diff options
Diffstat (limited to 'src/spdy2http/proxy.c')
-rw-r--r-- | src/spdy2http/proxy.c | 480 |
1 files changed, 363 insertions, 117 deletions
diff --git a/src/spdy2http/proxy.c b/src/spdy2http/proxy.c index 0c303823..e495cc72 100644 --- a/src/spdy2http/proxy.c +++ b/src/spdy2http/proxy.c | |||
@@ -21,6 +21,9 @@ | |||
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 | * No error handling for curl requests. | 23 | * No error handling for curl requests. |
24 | * TODO: | ||
25 | * - test all options! | ||
26 | * - don't abort on lack of memory | ||
24 | * @author Andrey Uzunov | 27 | * @author Andrey Uzunov |
25 | */ | 28 | */ |
26 | 29 | ||
@@ -36,6 +39,36 @@ | |||
36 | #include "microspdy.h" | 39 | #include "microspdy.h" |
37 | #include <curl/curl.h> | 40 | #include <curl/curl.h> |
38 | #include <assert.h> | 41 | #include <assert.h> |
42 | #include <getopt.h> | ||
43 | #include <regex.h> | ||
44 | |||
45 | |||
46 | struct global_options | ||
47 | { | ||
48 | char *http_backend; | ||
49 | char *cert; | ||
50 | char *cert_key; | ||
51 | uint16_t listen_port; | ||
52 | bool verbose; | ||
53 | bool curl_verbose; | ||
54 | bool transparent; | ||
55 | bool http10; | ||
56 | } glob_opt; | ||
57 | |||
58 | |||
59 | struct URI | ||
60 | { | ||
61 | char * full_uri; | ||
62 | char * scheme; | ||
63 | char * host_and_port; | ||
64 | //char * host_and_port_for_connecting; | ||
65 | char * host; | ||
66 | char * path; | ||
67 | char * path_and_more; | ||
68 | char * query; | ||
69 | char * fragment; | ||
70 | uint16_t port; | ||
71 | }; | ||
39 | 72 | ||
40 | 73 | ||
41 | #define PRINT_INFO(msg) do{\ | 74 | #define PRINT_INFO(msg) do{\ |
@@ -54,6 +87,26 @@ | |||
54 | while(0) | 87 | while(0) |
55 | 88 | ||
56 | 89 | ||
90 | #define PRINT_VERBOSE(msg) do{\ | ||
91 | if(glob_opt.verbose){\ | ||
92 | printf("%i:%s\n", __LINE__, msg);\ | ||
93 | fflush(stdout);\ | ||
94 | }\ | ||
95 | }\ | ||
96 | while(0) | ||
97 | |||
98 | |||
99 | #define PRINT_VERBOSE2(fmt, ...) do{\ | ||
100 | if(glob_opt.verbose){\ | ||
101 | printf("%i\n", __LINE__);\ | ||
102 | printf(fmt,##__VA_ARGS__);\ | ||
103 | printf("\n");\ | ||
104 | fflush(stdout);\ | ||
105 | }\ | ||
106 | }\ | ||
107 | while(0) | ||
108 | |||
109 | |||
57 | #define CURL_SETOPT(handle, opt, val) do{\ | 110 | #define CURL_SETOPT(handle, opt, val) do{\ |
58 | int ret; \ | 111 | int ret; \ |
59 | if(CURLE_OK != (ret = curl_easy_setopt(handle, opt, val))) \ | 112 | if(CURLE_OK != (ret = curl_easy_setopt(handle, opt, val))) \ |
@@ -63,17 +116,25 @@ | |||
63 | } \ | 116 | } \ |
64 | }\ | 117 | }\ |
65 | while(0) | 118 | while(0) |
119 | |||
66 | 120 | ||
121 | #define DIE(msg) do{\ | ||
122 | printf("FATAL ERROR (line %i): %s\n", __LINE__, msg);\ | ||
123 | fflush(stdout);\ | ||
124 | exit(EXIT_FAILURE);\ | ||
125 | }\ | ||
126 | while(0) | ||
67 | 127 | ||
68 | int run = 1; | 128 | |
69 | char* http_host; | 129 | int loop = 1; |
70 | CURLM *multi_handle; | 130 | CURLM *multi_handle; |
71 | int still_running = 0; /* keep number of running handles */ | 131 | int still_running = 0; /* keep number of running handles */ |
72 | int http10=0; | 132 | regex_t uri_preg; |
133 | |||
73 | 134 | ||
74 | struct Proxy | 135 | struct Proxy |
75 | { | 136 | { |
76 | char *path; | 137 | char *url; |
77 | struct SPDY_Request *request; | 138 | struct SPDY_Request *request; |
78 | struct SPDY_Response *response; | 139 | struct SPDY_Response *response; |
79 | CURL *curl_handle; | 140 | CURL *curl_handle; |
@@ -89,6 +150,114 @@ struct Proxy | |||
89 | }; | 150 | }; |
90 | 151 | ||
91 | 152 | ||
153 | void | ||
154 | free_uri(struct URI * uri) | ||
155 | { | ||
156 | if(NULL != uri) | ||
157 | { | ||
158 | free(uri->full_uri); | ||
159 | free(uri->scheme); | ||
160 | free(uri->host_and_port); | ||
161 | //free(uri->host_and_port_for_connecting); | ||
162 | free(uri->host); | ||
163 | free(uri->path); | ||
164 | free(uri->path_and_more); | ||
165 | free(uri->query); | ||
166 | free(uri->fragment); | ||
167 | uri->port = 0; | ||
168 | free(uri); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | int | ||
173 | init_parse_uri(regex_t * preg) | ||
174 | { | ||
175 | // RFC 2396 | ||
176 | // ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? | ||
177 | /* | ||
178 | scheme = $2 | ||
179 | authority = $4 | ||
180 | path = $5 | ||
181 | query = $7 | ||
182 | fragment = $9 | ||
183 | */ | ||
184 | |||
185 | return regcomp(preg, "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?", REG_EXTENDED); | ||
186 | } | ||
187 | |||
188 | void | ||
189 | deinit_parse_uri(regex_t * preg) | ||
190 | { | ||
191 | regfree(preg); | ||
192 | } | ||
193 | |||
194 | int | ||
195 | parse_uri(regex_t * preg, char * full_uri, struct URI ** uri) | ||
196 | { | ||
197 | int ret; | ||
198 | char *colon; | ||
199 | long long port; | ||
200 | size_t nmatch = 10; | ||
201 | regmatch_t pmatch[10]; | ||
202 | |||
203 | if (0 != (ret = regexec(preg, full_uri, nmatch, pmatch, 0))) | ||
204 | return ret; | ||
205 | |||
206 | *uri = malloc(sizeof(struct URI)); | ||
207 | if(NULL == *uri) | ||
208 | return -200; | ||
209 | |||
210 | (*uri)->full_uri = strdup(full_uri); | ||
211 | |||
212 | asprintf(&((*uri)->scheme), "%.*s",pmatch[2].rm_eo - pmatch[2].rm_so, &full_uri[pmatch[2].rm_so]); | ||
213 | asprintf(&((*uri)->host_and_port), "%.*s",pmatch[4].rm_eo - pmatch[4].rm_so, &full_uri[pmatch[4].rm_so]); | ||
214 | asprintf(&((*uri)->path), "%.*s",pmatch[5].rm_eo - pmatch[5].rm_so, &full_uri[pmatch[5].rm_so]); | ||
215 | asprintf(&((*uri)->path_and_more), "%.*s",pmatch[9].rm_eo - pmatch[5].rm_so, &full_uri[pmatch[5].rm_so]); | ||
216 | asprintf(&((*uri)->query), "%.*s",pmatch[7].rm_eo - pmatch[7].rm_so, &full_uri[pmatch[7].rm_so]); | ||
217 | asprintf(&((*uri)->fragment), "%.*s",pmatch[9].rm_eo - pmatch[9].rm_so, &full_uri[pmatch[9].rm_so]); | ||
218 | |||
219 | colon = strrchr((*uri)->host_and_port, ':'); | ||
220 | if(NULL == colon) | ||
221 | { | ||
222 | (*uri)->host = strdup((*uri)->host_and_port); | ||
223 | /*if(0 == strcasecmp("http", uri->scheme)) | ||
224 | { | ||
225 | uri->port = 80; | ||
226 | asprintf(&(uri->host_and_port_for_connecting), "%s:80", uri->host_and_port); | ||
227 | } | ||
228 | else if(0 == strcasecmp("https", uri->scheme)) | ||
229 | { | ||
230 | uri->port = 443; | ||
231 | asprintf(&(uri->host_and_port_for_connecting), "%s:443", uri->host_and_port); | ||
232 | } | ||
233 | else | ||
234 | { | ||
235 | PRINT_INFO("no standard scheme!"); | ||
236 | */(*uri)->port = 0; | ||
237 | /*uri->host_and_port_for_connecting = strdup(uri->host_and_port); | ||
238 | }*/ | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | port = atoi(colon + 1); | ||
243 | if(port<1 || port >= 256 * 256) | ||
244 | { | ||
245 | free_uri(*uri); | ||
246 | return -100; | ||
247 | } | ||
248 | (*uri)->port = port; | ||
249 | asprintf(&((*uri)->host), "%.*s", (int)(colon - (*uri)->host_and_port), (*uri)->host_and_port); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | |||
255 | static void catch_signal(int signal) | ||
256 | { | ||
257 | loop = 0; | ||
258 | } | ||
259 | |||
260 | |||
92 | ssize_t | 261 | ssize_t |
93 | response_callback (void *cls, | 262 | response_callback (void *cls, |
94 | void *buffer, | 263 | void *buffer, |
@@ -146,10 +315,6 @@ response_done_callback(void *cls, | |||
146 | struct Proxy *proxy = (struct Proxy *)cls; | 315 | struct Proxy *proxy = (struct Proxy *)cls; |
147 | int ret; | 316 | int ret; |
148 | 317 | ||
149 | //printf("response_done_callback\n"); | ||
150 | |||
151 | //printf("answer for %s was sent\n", (char *)cls); | ||
152 | |||
153 | if(SPDY_RESPONSE_RESULT_SUCCESS != status) | 318 | if(SPDY_RESPONSE_RESULT_SUCCESS != status) |
154 | { | 319 | { |
155 | printf("answer was NOT sent, %i\n",status); | 320 | printf("answer was NOT sent, %i\n",status); |
@@ -163,8 +328,7 @@ response_done_callback(void *cls, | |||
163 | 328 | ||
164 | SPDY_destroy_request(request); | 329 | SPDY_destroy_request(request); |
165 | SPDY_destroy_response(response); | 330 | SPDY_destroy_response(response); |
166 | if(!strcmp("/close",proxy->path)) run = 0; | 331 | free(proxy->url); |
167 | free(proxy->path); | ||
168 | free(proxy); | 332 | free(proxy); |
169 | } | 333 | } |
170 | 334 | ||
@@ -200,10 +364,7 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
200 | &response_callback, | 364 | &response_callback, |
201 | proxy, | 365 | proxy, |
202 | 0))) | 366 | 0))) |
203 | { | 367 | DIE("no response"); |
204 | PRINT_INFO("no response"); | ||
205 | abort(); | ||
206 | } | ||
207 | 368 | ||
208 | SPDY_name_value_destroy(proxy->headers); | 369 | SPDY_name_value_destroy(proxy->headers); |
209 | free(proxy->status_msg); | 370 | free(proxy->status_msg); |
@@ -215,10 +376,7 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
215 | false, | 376 | false, |
216 | &response_done_callback, | 377 | &response_done_callback, |
217 | proxy)) | 378 | proxy)) |
218 | { | 379 | DIE("no queue"); |
219 | PRINT_INFO("no queue"); | ||
220 | abort(); | ||
221 | } | ||
222 | 380 | ||
223 | return realsize; | 381 | return realsize; |
224 | } | 382 | } |
@@ -230,24 +388,15 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
230 | //version | 388 | //version |
231 | for(i=pos; i<realsize && ' '!=line[i]; ++i); | 389 | for(i=pos; i<realsize && ' '!=line[i]; ++i); |
232 | if(i == realsize) | 390 | if(i == realsize) |
233 | { | 391 | DIE("error on parsing headers"); |
234 | PRINT_INFO("error on parsing headers"); | ||
235 | abort(); | ||
236 | } | ||
237 | if(NULL == (proxy->version = strndup(line, i - pos))) | 392 | if(NULL == (proxy->version = strndup(line, i - pos))) |
238 | { | 393 | DIE("No memory"); |
239 | PRINT_INFO("no memory"); | ||
240 | abort(); | ||
241 | } | ||
242 | pos = i+1; | 394 | pos = i+1; |
243 | 395 | ||
244 | //status (number) | 396 | //status (number) |
245 | for(i=pos; i<realsize && ' '!=line[i] && '\r'!=line[i]; ++i); | 397 | for(i=pos; i<realsize && ' '!=line[i] && '\r'!=line[i]; ++i); |
246 | if(NULL == (status = strndup(&(line[pos]), i - pos))) | 398 | if(NULL == (status = strndup(&(line[pos]), i - pos))) |
247 | { | 399 | DIE("No memory"); |
248 | PRINT_INFO("no memory"); | ||
249 | abort(); | ||
250 | } | ||
251 | proxy->status = atoi(status); | 400 | proxy->status = atoi(status); |
252 | free(status); | 401 | free(status); |
253 | if(i<realsize && '\r'!=line[i]) | 402 | if(i<realsize && '\r'!=line[i]) |
@@ -256,10 +405,7 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
256 | pos = i+1; | 405 | pos = i+1; |
257 | for(i=pos; i<realsize && '\r'!=line[i]; ++i); | 406 | for(i=pos; i<realsize && '\r'!=line[i]; ++i); |
258 | if(NULL == (proxy->status_msg = strndup(&(line[pos]), i - pos))) | 407 | if(NULL == (proxy->status_msg = strndup(&(line[pos]), i - pos))) |
259 | { | 408 | DIE("No memory"); |
260 | PRINT_INFO("no memory"); | ||
261 | abort(); | ||
262 | } | ||
263 | } | 409 | } |
264 | return realsize; | 410 | return realsize; |
265 | } | 411 | } |
@@ -269,10 +415,7 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
269 | for(i=pos; i<realsize && ':'!=line[i] && '\r'!=line[i]; ++i) | 415 | for(i=pos; i<realsize && ':'!=line[i] && '\r'!=line[i]; ++i) |
270 | line[i] = tolower(line[i]); //spdy requires lower case | 416 | line[i] = tolower(line[i]); //spdy requires lower case |
271 | if(NULL == (name = strndup(line, i - pos))) | 417 | if(NULL == (name = strndup(line, i - pos))) |
272 | { | 418 | DIE("No memory"); |
273 | PRINT_INFO("no memory"); | ||
274 | abort(); | ||
275 | } | ||
276 | if(0 == strcmp(SPDY_HTTP_HEADER_CONNECTION, name) | 419 | if(0 == strcmp(SPDY_HTTP_HEADER_CONNECTION, name) |
277 | || 0 == strcmp(SPDY_HTTP_HEADER_KEEP_ALIVE, name)) | 420 | || 0 == strcmp(SPDY_HTTP_HEADER_KEEP_ALIVE, name)) |
278 | { | 421 | { |
@@ -284,10 +427,7 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
284 | { | 427 | { |
285 | //no value. is it possible? | 428 | //no value. is it possible? |
286 | if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, "")) | 429 | if(SPDY_YES != SPDY_name_value_add(proxy->headers, name, "")) |
287 | { | 430 | DIE("SPDY_name_value_add failed"); |
288 | PRINT_INFO("SPDY_name_value_add failed"); | ||
289 | abort(); | ||
290 | } | ||
291 | return realsize; | 431 | return realsize; |
292 | } | 432 | } |
293 | 433 | ||
@@ -296,10 +436,7 @@ curl_header_cb(void *ptr, size_t size, size_t nmemb, void *userp) | |||
296 | while(pos<realsize && isspace(line[pos])) ++pos; //remove leading space | 436 | while(pos<realsize && isspace(line[pos])) ++pos; //remove leading space |
297 | for(i=pos; i<realsize && '\r'!=line[i]; ++i); | 437 | for(i=pos; i<realsize && '\r'!=line[i]; ++i); |
298 | if(NULL == (value = strndup(&(line[pos]), i - pos))) | 438 | if(NULL == (value = strndup(&(line[pos]), i - pos))) |
299 | { | 439 | DIE("No memory"); |
300 | PRINT_INFO("no memory"); | ||
301 | abort(); | ||
302 | } | ||
303 | if(SPDY_YES != (ret = SPDY_name_value_add(proxy->headers, name, value))) | 440 | if(SPDY_YES != (ret = SPDY_name_value_add(proxy->headers, name, value))) |
304 | { | 441 | { |
305 | abort_it=true; | 442 | abort_it=true; |
@@ -365,12 +502,8 @@ iterate_cb (void *cls, const char *name, const char * const * value, int num_val | |||
365 | line_len += strlen(value[i]); | 502 | line_len += strlen(value[i]); |
366 | } | 503 | } |
367 | 504 | ||
368 | if(NULL == (line = malloc(line_len))) | 505 | if(NULL == (line = malloc(line_len)))//no recovery |
369 | { | 506 | DIE("No memory"); |
370 | //no recovory | ||
371 | PRINT_INFO("no memory"); | ||
372 | abort(); | ||
373 | } | ||
374 | line[0] = 0; | 507 | line[0] = 0; |
375 | 508 | ||
376 | strcat(line, name); | 509 | strcat(line, name); |
@@ -384,11 +517,8 @@ iterate_cb (void *cls, const char *name, const char * const * value, int num_val | |||
384 | if(i) strcat(line, ", "); | 517 | if(i) strcat(line, ", "); |
385 | strcat(line, value[i]); | 518 | strcat(line, value[i]); |
386 | } | 519 | } |
387 | if(NULL == (*curl_headers = curl_slist_append(*curl_headers, line))) | 520 | if(NULL == (*curl_headers = curl_slist_append(*curl_headers, line))) |
388 | { | 521 | DIE("curl_slist_append failed"); |
389 | PRINT_INFO("curl_slist_append failed"); | ||
390 | abort(); | ||
391 | } | ||
392 | free(line); | 522 | free(line); |
393 | 523 | ||
394 | return SPDY_YES; | 524 | return SPDY_YES; |
@@ -411,43 +541,54 @@ standard_request_handler(void *cls, | |||
411 | (void)host; | 541 | (void)host; |
412 | (void)scheme; | 542 | (void)scheme; |
413 | 543 | ||
414 | char *url; | ||
415 | struct Proxy *proxy; | 544 | struct Proxy *proxy; |
416 | int ret; | 545 | int ret; |
546 | struct URI *uri; | ||
417 | 547 | ||
418 | //printf("received request for '%s %s %s'\n", method, path, version); | 548 | PRINT_VERBOSE2("received request for '%s %s %s'\n", method, path, version); |
419 | if(NULL == (proxy = malloc(sizeof(struct Proxy)))) | 549 | if(NULL == (proxy = malloc(sizeof(struct Proxy)))) |
420 | { | 550 | DIE("No memory"); |
421 | PRINT_INFO("No memory"); | ||
422 | abort(); | ||
423 | } | ||
424 | memset(proxy, 0, sizeof(struct Proxy)); | 551 | memset(proxy, 0, sizeof(struct Proxy)); |
425 | proxy->request = request; | 552 | proxy->request = request; |
426 | if(NULL == (proxy->headers = SPDY_name_value_create())) | 553 | if(NULL == (proxy->headers = SPDY_name_value_create())) |
427 | { | 554 | DIE("No memory"); |
428 | PRINT_INFO("No memory"); | 555 | |
429 | abort(); | 556 | if(glob_opt.transparent) |
430 | } | 557 | { |
431 | 558 | if(NULL != glob_opt.http_backend) //use always same host | |
432 | //TODO add https | 559 | ret = asprintf(&(proxy->url),"%s://%s%s", scheme, glob_opt.http_backend, path); |
433 | if(0 == strcmp(http_host, "any")) | 560 | else //use host header |
434 | ret = asprintf(&url,"%s%s%s","http://", host, path); | 561 | ret = asprintf(&(proxy->url),"%s://%s%s", scheme, host, path); |
435 | else | 562 | if(-1 == ret) |
436 | ret = asprintf(&url,"%s%s%s","http://", http_host, path); | 563 | DIE("No memory"); |
437 | 564 | ||
438 | if(-1 == ret) | 565 | ret = parse_uri(&uri_preg, proxy->url, &uri); |
439 | { | 566 | if(ret != 0) |
440 | PRINT_INFO("No memory"); | 567 | DIE("parsing built uri failed"); |
441 | abort(); | 568 | } |
442 | } | 569 | else |
443 | 570 | { | |
444 | if(NULL == (proxy->path = strdup(path))) | 571 | ret = parse_uri(&uri_preg, path, &uri); |
445 | { | 572 | PRINT_INFO2("path %s '%s' '%s'", path, uri->scheme, uri->host); |
446 | PRINT_INFO("No memory"); | 573 | if(ret != 0 || !strlen(uri->scheme) || !strlen(uri->host)) |
447 | abort(); | 574 | DIE("parsing received uri failed"); |
448 | } | 575 | |
576 | if(NULL != glob_opt.http_backend) //use backend host | ||
577 | { | ||
578 | ret = asprintf(&(proxy->url),"%s://%s%s", uri->scheme, glob_opt.http_backend, uri->path_and_more); | ||
579 | if(-1 == ret) | ||
580 | DIE("No memory"); | ||
581 | } | ||
582 | else //use request path | ||
583 | if(NULL == (proxy->url = strdup(path))) | ||
584 | DIE("No memory"); | ||
585 | } | ||
586 | |||
587 | free(uri); | ||
588 | |||
589 | PRINT_VERBOSE2("curl will request '%s'", proxy->url); | ||
449 | 590 | ||
450 | SPDY_name_value_iterate(headers, &iterate_cb, proxy); | 591 | SPDY_name_value_iterate(headers, &iterate_cb, proxy); |
451 | 592 | ||
452 | if(NULL == (proxy->curl_handle = curl_easy_init())) | 593 | if(NULL == (proxy->curl_handle = curl_easy_init())) |
453 | { | 594 | { |
@@ -455,10 +596,10 @@ standard_request_handler(void *cls, | |||
455 | abort(); | 596 | abort(); |
456 | } | 597 | } |
457 | 598 | ||
458 | //CURL_SETOPT(proxy->curl_handle, CURLOPT_VERBOSE, 1); | 599 | if(glob_opt.curl_verbose) |
459 | CURL_SETOPT(proxy->curl_handle, CURLOPT_URL, url); | 600 | CURL_SETOPT(proxy->curl_handle, CURLOPT_VERBOSE, 1); |
460 | free(url); | 601 | CURL_SETOPT(proxy->curl_handle, CURLOPT_URL, proxy->url); |
461 | if(http10) | 602 | if(glob_opt.http10) |
462 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | 603 | CURL_SETOPT(proxy->curl_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); |
463 | CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEFUNCTION, curl_write_cb); | 604 | CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEFUNCTION, curl_write_cb); |
464 | CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEDATA, proxy); | 605 | CURL_SETOPT(proxy->curl_handle, CURLOPT_WRITEDATA, proxy); |
@@ -484,9 +625,9 @@ standard_request_handler(void *cls, | |||
484 | } | 625 | } |
485 | 626 | ||
486 | int | 627 | int |
487 | main (int argc, char *const *argv) | 628 | run() |
488 | { | 629 | { |
489 | unsigned long long timeoutlong=0; | 630 | unsigned long long timeoutlong=0; |
490 | long curl_timeo = -1; | 631 | long curl_timeo = -1; |
491 | struct timeval timeout; | 632 | struct timeval timeout; |
492 | int ret; | 633 | int ret; |
@@ -504,20 +645,18 @@ main (int argc, char *const *argv) | |||
504 | 645 | ||
505 | signal(SIGPIPE, SIG_IGN); | 646 | signal(SIGPIPE, SIG_IGN); |
506 | 647 | ||
507 | if(argc != 6) | 648 | if (signal(SIGINT, catch_signal) == SIG_ERR) |
508 | { | 649 | PRINT_VERBOSE("signal failed"); |
509 | printf("Usage: %s cert-file key-file host port http/1.0(yes/no)\n\ | 650 | |
510 | \n\ | 651 | srand(time(NULL)); |
511 | Example for transparent proxy (':host' header is used to know which HTTP server to connect):\n\ | 652 | if(init_parse_uri(&uri_preg)) |
512 | %s cert.pem key.pem any 8080 no\n", argv[0], argv[0]); | 653 | DIE("Regexp compilation failed"); |
513 | return 1; | 654 | |
514 | } | ||
515 | |||
516 | SPDY_init(); | 655 | SPDY_init(); |
517 | 656 | ||
518 | daemon = SPDY_start_daemon(atoi(argv[4]), | 657 | daemon = SPDY_start_daemon(glob_opt.listen_port, |
519 | argv[1], | 658 | glob_opt.cert, |
520 | argv[2], | 659 | glob_opt.cert_key, |
521 | NULL, | 660 | NULL, |
522 | NULL, | 661 | NULL, |
523 | &standard_request_handler, | 662 | &standard_request_handler, |
@@ -533,21 +672,13 @@ Example for transparent proxy (':host' header is used to know which HTTP server | |||
533 | } | 672 | } |
534 | 673 | ||
535 | multi_handle = curl_multi_init(); | 674 | multi_handle = curl_multi_init(); |
536 | 675 | if(NULL==multi_handle) | |
537 | if(NULL==multi_handle){ | 676 | DIE("no multi_handle"); |
538 | PRINT_INFO("no multi_handle"); | 677 | |
539 | abort(); | ||
540 | } | ||
541 | |||
542 | if(!strcmp("yes", argv[5])) | ||
543 | http10 = 1; | ||
544 | |||
545 | http_host = argv[3]; | ||
546 | timeout.tv_usec = 0; | 678 | timeout.tv_usec = 0; |
547 | 679 | ||
548 | do | 680 | do |
549 | { | 681 | { |
550 | //printf("still %i\n", still_running); | ||
551 | FD_ZERO(&rs); | 682 | FD_ZERO(&rs); |
552 | FD_ZERO(&ws); | 683 | FD_ZERO(&ws); |
553 | FD_ZERO(&es); | 684 | FD_ZERO(&es); |
@@ -653,14 +784,129 @@ Example for transparent proxy (':host' header is used to know which HTTP server | |||
653 | else PRINT_INFO("shouldn't happen"); | 784 | else PRINT_INFO("shouldn't happen"); |
654 | } | 785 | } |
655 | } | 786 | } |
656 | while(run); | 787 | while(loop); |
657 | 788 | ||
658 | curl_multi_cleanup(multi_handle); | 789 | curl_multi_cleanup(multi_handle); |
659 | 790 | ||
660 | SPDY_stop_daemon(daemon); | 791 | SPDY_stop_daemon(daemon); |
661 | 792 | ||
662 | SPDY_deinit(); | 793 | SPDY_deinit(); |
794 | |||
795 | deinit_parse_uri(&uri_preg); | ||
663 | 796 | ||
664 | return 0; | 797 | return 0; |
665 | } | 798 | } |
666 | 799 | ||
800 | void | ||
801 | display_usage() | ||
802 | { | ||
803 | printf( | ||
804 | "Usage: microspdy2http [-vh0t] [-b <HTTP-SERVER>] -p <PORT> -c <CERTIFICATE> -k <CERT-KEY>\n\n" | ||
805 | "OPTIONS:\n" | ||
806 | " -p, --port Listening port.\n" | ||
807 | " -c, --certificate Path to a certificate file.\n" | ||
808 | " -k, --certificate-key Path to a key file for the certificate.\n" | ||
809 | " -b, --backend-server If set, the proxy will connect always to it.\n" | ||
810 | " Otherwise the proxy will connect to the URL\n" | ||
811 | " which is specified in the path or 'Host:'.\n" | ||
812 | " -v, --verbose Print debug information.\n" | ||
813 | " -h, --curl-verbose Print debug information for curl.\n" | ||
814 | " -0, --http10 Prefer HTTP/1.0 connections to the next hop.\n" | ||
815 | " -t, --transparent If set, the proxy will fetch an URL which\n" | ||
816 | " is based on 'Host:' header and requested path.\n" | ||
817 | " Otherwise, full URL in the requested path is required.\n\n" | ||
818 | |||
819 | ); | ||
820 | } | ||
821 | |||
822 | int | ||
823 | main (int argc, char *const *argv) | ||
824 | { | ||
825 | |||
826 | int getopt_ret; | ||
827 | int option_index; | ||
828 | struct option long_options[] = { | ||
829 | {"port", required_argument, 0, 'p'}, | ||
830 | {"certificate", required_argument, 0, 'c'}, | ||
831 | {"certificate-key", required_argument, 0, 'k'}, | ||
832 | {"backend-server", required_argument, 0, 'b'}, | ||
833 | {"verbose", no_argument, 0, 'v'}, | ||
834 | {"curl-verbose", no_argument, 0, 'h'}, | ||
835 | {"http10", no_argument, 0, '0'}, | ||
836 | {"transparent", no_argument, 0, 't'}, | ||
837 | {0, 0, 0, 0} | ||
838 | }; | ||
839 | |||
840 | while (1) | ||
841 | { | ||
842 | getopt_ret = getopt_long( argc, argv, "p:c:k:b:v0t", long_options, &option_index); | ||
843 | if (getopt_ret == -1) | ||
844 | break; | ||
845 | |||
846 | switch(getopt_ret) | ||
847 | { | ||
848 | case 'p': | ||
849 | glob_opt.listen_port = atoi(optarg); | ||
850 | break; | ||
851 | |||
852 | case 'c': | ||
853 | glob_opt.cert = strdup(optarg); | ||
854 | if(NULL == glob_opt.cert) | ||
855 | return 1; | ||
856 | break; | ||
857 | |||
858 | case 'k': | ||
859 | glob_opt.cert_key = strdup(optarg); | ||
860 | if(NULL == glob_opt.cert_key) | ||
861 | return 1; | ||
862 | break; | ||
863 | |||
864 | case 'b': | ||
865 | glob_opt.http_backend = strdup(optarg); | ||
866 | if(NULL == glob_opt.http_backend) | ||
867 | return 1; | ||
868 | break; | ||
869 | |||
870 | case 'v': | ||
871 | glob_opt.verbose = true; | ||
872 | break; | ||
873 | |||
874 | case 'h': | ||
875 | glob_opt.curl_verbose = true; | ||
876 | break; | ||
877 | |||
878 | case '0': | ||
879 | glob_opt.http10 = true; | ||
880 | break; | ||
881 | |||
882 | case 't': | ||
883 | glob_opt.transparent = true; | ||
884 | break; | ||
885 | |||
886 | case 0: | ||
887 | PRINT_INFO("0 from getopt"); | ||
888 | break; | ||
889 | |||
890 | case '?': | ||
891 | display_usage(); | ||
892 | return 1; | ||
893 | |||
894 | default: | ||
895 | DIE("default from getopt"); | ||
896 | } | ||
897 | } | ||
898 | |||
899 | if( | ||
900 | 0 == glob_opt.listen_port | ||
901 | || NULL == glob_opt.cert | ||
902 | || NULL == glob_opt.cert_key | ||
903 | //|| !glob_opt.transparent && NULL != glob_opt.http_backend | ||
904 | ) | ||
905 | { | ||
906 | display_usage(); | ||
907 | return 1; | ||
908 | } | ||
909 | |||
910 | return run(); | ||
911 | } | ||
912 | |||