/* Allocates memory into the block self. Return null if failiure, and self on success. */ au_mem * au_mem_malloc(au_mem * self, au_size_t size) { void * ptr; if(!self) { return NULL; } ptr = au_malloc(size); if(!ptr) { return NULL; } return au_mem_wrap(self, ptr); }
int parse_uri(regex_t * preg, char * full_uri, struct URI ** uri) { int ret; char *colon; long long port; size_t nmatch = 10; regmatch_t pmatch[10]; if (0 != (ret = regexec(preg, full_uri, nmatch, pmatch, 0))) return ret; *uri = au_malloc(sizeof(struct URI)); if(NULL == *uri) return -200; (*uri)->full_uri = strdup(full_uri); asprintf(&((*uri)->scheme), "%.*s",pmatch[2].rm_eo - pmatch[2].rm_so, &full_uri[pmatch[2].rm_so]); asprintf(&((*uri)->host_and_port), "%.*s",pmatch[4].rm_eo - pmatch[4].rm_so, &full_uri[pmatch[4].rm_so]); asprintf(&((*uri)->path), "%.*s",pmatch[5].rm_eo - pmatch[5].rm_so, &full_uri[pmatch[5].rm_so]); asprintf(&((*uri)->path_and_more), "%.*s",pmatch[9].rm_eo - pmatch[5].rm_so, &full_uri[pmatch[5].rm_so]); asprintf(&((*uri)->query), "%.*s",pmatch[7].rm_eo - pmatch[7].rm_so, &full_uri[pmatch[7].rm_so]); asprintf(&((*uri)->fragment), "%.*s",pmatch[9].rm_eo - pmatch[9].rm_so, &full_uri[pmatch[9].rm_so]); colon = strrchr((*uri)->host_and_port, ':'); if(NULL == colon) { (*uri)->host = strdup((*uri)->host_and_port); /*if(0 == strcasecmp("http", uri->scheme)) { uri->port = 80; asprintf(&(uri->host_and_port_for_connecting), "%s:80", uri->host_and_port); } else if(0 == strcasecmp("https", uri->scheme)) { uri->port = 443; asprintf(&(uri->host_and_port_for_connecting), "%s:443", uri->host_and_port); } else { PRINT_INFO("no standard scheme!"); */(*uri)->port = 0; /*uri->host_and_port_for_connecting = strdup(uri->host_and_port); }*/ return 0; } port = atoi(colon + 1); if(port<1 || port >= 256 * 256) { free_uri(*uri); return -100; } (*uri)->port = port; asprintf(&((*uri)->host), "%.*s", (int)(colon - (*uri)->host_and_port), (*uri)->host_and_port); return 0; }
static au_str au_str_set_cstr(au_str self, const char * cstr, size_t size) { if(!self) { return self; } au_str_empty(self); if(!cstr) { return self; } self->cstr = (char *) au_malloc(size); if(!self->cstr) { self->size = 0; return NULL; } strncpy(self->cstr, cstr, size); /* And copy the data. */ return self; }
void * http_cb_log(void * cls, const char * uri) { (void)cls; struct HTTP_URI * http_uri; PRINT_INFO2("log uri '%s'\n", uri); //TODO not freed once in a while if(NULL == (http_uri = au_malloc(sizeof(struct HTTP_URI )))) return NULL; http_uri->uri = strdup(uri); return http_uri; }
static ssize_t http_cb_response (void *cls, uint64_t pos, char *buffer, size_t max) { (void)pos; int ret; struct Proxy *proxy = (struct Proxy *)cls; void *newbody; const union MHD_ConnectionInfo *info; int val = 1; PRINT_INFO2("http_cb_response for %s", proxy->url); if(proxy->spdy_error) return MHD_CONTENT_READER_END_WITH_ERROR; if(0 == proxy->http_body_size && (proxy->done || !proxy->spdy_active)) { PRINT_INFO("sent end of stream"); return MHD_CONTENT_READER_END_OF_STREAM; } if(!proxy->http_body_size)//nothing to write now { //flush data info = MHD_get_connection_info (proxy->http_connection, MHD_CONNECTION_INFO_CONNECTION_FD); ret = setsockopt(info->connect_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)); if(ret == -1) { DIE("setsockopt"); } PRINT_INFO("FLUSH data"); return 0; } if(max >= proxy->http_body_size) { ret = proxy->http_body_size; newbody = NULL; } else { ret = max; if(NULL == (newbody = au_malloc(proxy->http_body_size - max))) { PRINT_INFO("no memory"); return MHD_CONTENT_READER_END_WITH_ERROR; } memcpy(newbody, proxy->http_body + max, proxy->http_body_size - max); } memcpy(buffer, proxy->http_body, ret); free(proxy->http_body); proxy->http_body = newbody; proxy->http_body_size -= ret; if(proxy->length >= 0) { proxy->length -= ret; } PRINT_INFO2("response_callback, size: %i",ret); return ret; }
int http_cb_request (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **ptr) { (void)cls; (void)url; (void)upload_data; (void)upload_data_size; int ret; struct Proxy *proxy; struct SPDY_Headers spdy_headers; bool with_body = false; struct HTTP_URI *http_uri; const char *header_value; if (NULL == ptr || NULL == *ptr) return MHD_NO; http_uri = (struct HTTP_URI *)*ptr; if(NULL == http_uri->proxy) { //first call for this request if (0 != strcmp (method, MHD_HTTP_METHOD_GET) && 0 != strcmp (method, MHD_HTTP_METHOD_POST)) { free(http_uri->uri); free(http_uri); PRINT_INFO2("unexpected method %s", method); return MHD_NO; } if(NULL == (proxy = au_malloc(sizeof(struct Proxy)))) { free(http_uri->uri); free(http_uri); PRINT_INFO("No memory"); return MHD_NO; } ++glob_opt.responses_pending; proxy->id = rand(); proxy->http_active = true; proxy->http_connection = connection; http_uri->proxy = proxy; return MHD_YES; } proxy = http_uri->proxy; if(proxy->spdy_error || proxy->http_error) return MHD_NO; // handled at different place TODO? leaks? if(proxy->spdy_active) { if(0 == strcmp (method, MHD_HTTP_METHOD_POST)) { PRINT_INFO("POST processing"); int rc= spdylay_session_resume_data(proxy->spdy_connection->session, proxy->stream_id); PRINT_INFO2("rc is %i stream is %i", rc, proxy->stream_id); proxy->spdy_connection->want_io |= WANT_WRITE; if(0 == *upload_data_size) { PRINT_INFO("POST http EOF"); proxy->receiving_done = true; return MHD_YES; } if(!copy_buffer(upload_data, *upload_data_size, &proxy->received_body, &proxy->received_body_size)) { //TODO handle it better? PRINT_INFO("not enough memory (malloc/realloc returned NULL)"); return MHD_NO; } *upload_data_size = 0; return MHD_YES; } //already handled PRINT_INFO("unnecessary call to http_cb_request"); return MHD_YES; } //second call for this request PRINT_INFO2("received request for '%s %s %s'", method, http_uri->uri, version); proxy->url = http_uri->uri; header_value = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_LENGTH); with_body = 0 == strcmp (method, MHD_HTTP_METHOD_POST) && (NULL == header_value || 0 != strcmp ("0", header_value)); PRINT_INFO2("body will be sent %i", with_body); ret = parse_uri(&glob_opt.uri_preg, proxy->url, &proxy->uri); if(ret != 0) DIE("parse_uri failed"); proxy->http_uri = http_uri; spdy_headers.num = MHD_get_connection_values (connection, MHD_HEADER_KIND, NULL, NULL); if(NULL == (spdy_headers.nv = au_malloc(((spdy_headers.num + 5) * 2 + 1) * sizeof(char *)))) DIE("no memory"); spdy_headers.nv[0] = ":method"; spdy_headers.nv[1] = method; spdy_headers.nv[2] = ":path"; spdy_headers.nv[3] = proxy->uri->path_and_more; spdy_headers.nv[4] = ":version"; spdy_headers.nv[5] = (char *)version; spdy_headers.nv[6] = ":scheme"; spdy_headers.nv[7] = proxy->uri->scheme; spdy_headers.nv[8] = ":host"; spdy_headers.nv[9] = NULL; //nv[14] = NULL; spdy_headers.cnt = 10; MHD_get_connection_values (connection, MHD_HEADER_KIND, &http_cb_iterate, &spdy_headers); spdy_headers.nv[spdy_headers.cnt] = NULL; if(NULL == spdy_headers.nv[9]) spdy_headers.nv[9] = proxy->uri->host_and_port; if(0 != spdy_request(spdy_headers.nv, proxy, with_body)) { free(spdy_headers.nv); //free_proxy(proxy); return MHD_NO; } free(spdy_headers.nv); proxy->http_response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 4096, &http_cb_response, proxy, &http_cb_response_done); if (NULL == proxy->http_response) DIE("no response"); if(MHD_NO == MHD_add_response_header (proxy->http_response, "Proxy-Connection", "keep-alive")) PRINT_INFO("SPDY_name_value_add failed: "); if(MHD_NO == MHD_add_response_header (proxy->http_response, "Connection", "Keep-Alive")) PRINT_INFO("SPDY_name_value_add failed: "); if(MHD_NO == MHD_add_response_header (proxy->http_response, "Keep-Alive", "timeout=5, max=100")) PRINT_INFO("SPDY_name_value_add failed: "); proxy->spdy_active = true; return MHD_YES; }
/* Allocates a new, empty memory block. */ au_mem * au_mem_alloc() { au_mem * self; result = au_malloc(sizeof(* self)); return result; }
/* * Fetches the resource denoted by |uri|. */ struct SPDY_Connection * spdy_connect(const struct URI *uri, uint16_t port, bool is_tls) { spdylay_session_callbacks callbacks; int fd; SSL *ssl=NULL; struct SPDY_Connection * connection = NULL; int rv; spdy_setup_spdylay_callbacks(&callbacks); /* Establish connection and setup SSL */ PRINT_INFO2("connecting to %s:%i", uri->host, port); fd = spdy_socket_connect_to(uri->host, port); if(fd == -1) { PRINT_INFO("Could not open file descriptor"); return NULL; } if(is_tls) { ssl = SSL_new(glob_opt.ssl_ctx); if(ssl == NULL) { spdy_dief("SSL_new", ERR_error_string(ERR_get_error(), NULL)); } //TODO non-blocking /* To simplify the program, we perform SSL/TLS handshake in blocking I/O. */ glob_opt.spdy_proto_version = 0; rv = spdy_ssl_handshake(ssl, fd); if(rv <= 0 || (glob_opt.spdy_proto_version != 3 && glob_opt.spdy_proto_version != 2)) { PRINT_INFO("Closing SSL"); //no spdy on the other side goto free_and_fail; } } else { glob_opt.spdy_proto_version = 3; } if(NULL == (connection = au_malloc(sizeof(struct SPDY_Connection)))) goto free_and_fail; connection->is_tls = is_tls; connection->ssl = ssl; connection->want_io = IO_NONE; if(NULL == (connection->host = strdup(uri->host))) goto free_and_fail; /* Here make file descriptor non-block */ spdy_socket_make_non_block(fd); spdy_socket_set_tcp_nodelay(fd); PRINT_INFO2("[INFO] SPDY protocol version = %d\n", glob_opt.spdy_proto_version); rv = spdylay_session_client_new(&(connection->session), glob_opt.spdy_proto_version, &callbacks, connection); if(rv != 0) { spdy_diec("spdylay_session_client_new", rv); } connection->fd = fd; return connection; //for GOTO free_and_fail: if(NULL != connection) { free(connection->host); free(connection); } if(is_tls) SSL_shutdown(ssl); MHD_socket_close_ (fd); if(is_tls) SSL_free(ssl); return NULL; }