int connection_http_to_proxy(Connection *conn) { Proxy *proxy = Request_get_action(conn->req, proxy); check(proxy != NULL, "Should have a proxy backend."); int proxy_fd = netdial(1, bdata(proxy->server), proxy->port); check(proxy_fd != -1, "Failed to connect to proxy backend %s:%d", bdata(proxy->server), proxy->port); if(!conn->proxy_iob) { conn->proxy_iob = IOBuf_create(BUFFER_SIZE, proxy_fd, IOBUF_SOCKET); check_mem(conn->proxy_iob); } if(!conn->client) { conn->client = h_calloc(sizeof(httpclient_parser), 1); check_mem(conn->client); hattach(conn->client, conn); } return CONNECT; error: return FAILED; }
int connection_msg_to_handler(Connection *conn) { Handler *handler = Request_get_action(conn->req, handler); int rc = 0; int header_len = Request_header_length(conn->req); // body_len will include \0 int body_len = Request_content_length(conn->req); check(handler, "JSON request doesn't match any handler: %s", bdata(Request_path(conn->req))); if(pattern_match(IOBuf_start(conn->iob), header_len + body_len, bdata(&PING_PATTERN))) { Register_ping(IOBuf_fd(conn->iob)); } else { check(body_len >= 0, "Parsing error, body length ended up being: %d", body_len); bstring payload = Request_to_payload(conn->req, handler->send_ident, IOBuf_fd(conn->iob), IOBuf_start(conn->iob) + header_len, body_len - 1); // drop \0 on payloads rc = Handler_deliver(handler->send_socket, bdata(payload), blength(payload)); bdestroy(payload); check(rc == 0, "Failed to deliver to handler: %s", bdata(Request_path(conn->req))); } // consumes \0 from body_len IOBuf_read_commit(conn->iob, header_len + body_len); return REQ_SENT; error: return CLOSE; }
int connection_proxy_reply_parse(Connection *conn) { int rc = 0; int total = 0; Proxy *proxy = Request_get_action(conn->req, proxy); httpclient_parser *client = conn->client; rc = Proxy_read_and_parse(conn); check(rc != -1, "Failed to read from proxy server: %s:%d", bdata(proxy->server), proxy->port); if(client->chunked) { // send the http header we have so far rc = IOBuf_stream(conn->proxy_iob, conn->iob, client->body_start); check_debug(rc != -1, "Failed streaming header to client."); // then just stream out the chunks we've got, as long as // Proxy_stream_chunks return 0 it means we've got more to send do { rc = Proxy_stream_chunks(conn); check(rc != -1, "Failed to stream chunked encoding to client."); } while(rc == 0); } else if(client->content_len >= 0) { total = client->body_start + client->content_len; rc = IOBuf_stream(conn->proxy_iob, conn->iob, total); check(rc != -1, "Failed streaming non-chunked response."); } else if(client->status == 204 || client->status == 304) { // According to the RFC, these MUST NOT incude a body. // Proxy might keep the connection open but not send content-length. rc = IOBuf_stream(conn->proxy_iob, conn->iob, client->body_start); check(rc != -1, "Failed streaming non-chunked response."); } else if(client->close || client->content_len == -1) { debug("Response requested a read until close."); Proxy_stream_to_close(conn); } else { sentinel("Should not reach this code, Tell Zed."); } Log_request(conn, client->status, client->content_len); if(client->close) { return REMOTE_CLOSE; } else { return REQ_RECV; } error: return FAILED; }
int connection_msg_to_handler(Connection *conn) { Handler *handler = Request_get_action(conn->req, handler); int rc = 0; int header_len = Request_header_length(conn->req); // body_len will include \0 int body_len = Request_content_length(conn->req); check(handler, "JSON request doesn't match any handler: %s", bdata(Request_path(conn->req))); if(pattern_match(IOBuf_start(conn->iob), header_len + body_len, bdata(&PING_PATTERN))) { Register_ping(IOBuf_fd(conn->iob)); } else { check(body_len >= 0, "Parsing error, body length ended up being: %d", body_len); bstring payload = NULL; if(handler->protocol == HANDLER_PROTO_TNET) { payload = Request_to_tnetstring(conn->req, handler->send_ident, IOBuf_fd(conn->iob), IOBuf_start(conn->iob) + header_len, body_len - 1); // drop \0 on payloads } else if(handler->protocol == HANDLER_PROTO_JSON) { payload = Request_to_payload(conn->req, handler->send_ident, IOBuf_fd(conn->iob), IOBuf_start(conn->iob) + header_len, body_len - 1); // drop \0 on payloads } else { sentinel("Invalid protocol type: %d", handler->protocol); } debug("SENT: %s", bdata(payload)); check(payload != NULL, "Failed to generate payload."); check(handler->send_socket != NULL, "Handler socket is NULL, tell Zed."); rc = Handler_deliver(handler->send_socket, bdata(payload), blength(payload)); free(payload); check(rc == 0, "Failed to deliver to handler: %s", bdata(Request_path(conn->req))); } // consumes \0 from body_len check(IOBuf_read_commit(conn->iob, header_len + body_len) != -1, "Final commit failed."); return REQ_SENT; error: return CLOSE; }
int connection_http_to_handler(Connection *conn) { int content_len = Request_content_length(conn->req); int rc = 0; char *body = NULL; Handler *handler = Request_get_action(conn->req, handler); error_unless(handler, conn, 404, "No action for request: %s", bdata(Request_path(conn->req))); // we don't need the header anymore, so commit the buffer and deal with the body IOBuf_read_commit(conn->iob, Request_header_length(conn->req)); if(content_len == 0) { body = ""; rc = Connection_send_to_handler(conn, handler, body, content_len); check_debug(rc == 0, "Failed to deliver to the handler."); } else if(content_len > MAX_CONTENT_LENGTH) { rc = Upload_file(conn, handler, content_len); check(rc == 0, "Failed to upload file."); } else { if(content_len > conn->iob->len) { // temporarily grow the buffer IOBuf_resize(conn->iob, content_len); } debug("READ ALL CALLED with content_len: %d, and MAX_CONTENT_LENGTH: %d", content_len, MAX_CONTENT_LENGTH); body = IOBuf_read_all(conn->iob, content_len, CLIENT_READ_RETRIES); check(body != NULL, "Client closed the connection during upload."); rc = Connection_send_to_handler(conn, handler, body, content_len); check_debug(rc == 0, "Failed to deliver to the handler."); } Log_request(conn, 200, content_len); return REQ_SENT; error: return CLOSE; }
int connection_http_to_directory(Connection *conn) { Dir *dir = Request_get_action(conn->req, dir); int rc = Dir_serve_file(dir, conn->req, conn); check_debug(rc == 0, "Failed to serve file: %s", bdata(Request_path(conn->req))); IOBuf_read_commit(conn->iob, Request_header_length(conn->req) + Request_content_length(conn->req)); Log_request(conn, conn->req->status_code, conn->req->response_size); if(conn->close) { return CLOSE; } else { return RESP_SENT; } error: return CLOSE; }
int connection_http_to_handler(Connection *conn) { int content_len = Request_content_length(conn->req); int rc = 0; char *body = NULL; Handler *handler = Request_get_action(conn->req, handler); error_unless(handler, conn, 404, "No action for request: %s", bdata(Request_path(conn->req))); bstring expects = Request_get(conn->req, &HTTP_EXPECT); if (expects != NULL) { if (biseqcstr(expects, "100-continue")) { Response_send_status(conn, &HTTP_100); } else { Response_send_status(conn, &HTTP_417); log_info("Client requested unsupported expectation: %s.", bdata(expects)); goto error; } } // we don't need the header anymore, so commit the buffer and deal with the body check(IOBuf_read_commit(conn->iob, Request_header_length(conn->req)) != -1, "Finaly commit failed streaming the connection to http handlers."); if(is_websocket(conn)) { bstring wsKey = Request_get(conn->req, &WS_SEC_WS_KEY); bstring response= websocket_challenge(wsKey); conn->handler = handler; //Response_send_status(conn,response); bdestroy(conn->req->request_method); conn->req->request_method=bfromcstr("WEBSOCKET_HANDSHAKE"); Connection_send_to_handler(conn, handler, bdata(response), blength(response)); bdestroy(response); bdestroy(conn->req->request_method); conn->req->request_method=bfromcstr("WEBSOCKET"); return REQ_SENT; } if(content_len == 0) { body = ""; rc = Connection_send_to_handler(conn, handler, body, content_len); check_debug(rc == 0, "Failed to deliver to the handler."); } else if(content_len > MAX_CONTENT_LENGTH) { rc = Upload_file(conn, handler, content_len); check(rc == 0, "Failed to upload file."); } else { debug("READ ALL CALLED with content_len: %d, and MAX_CONTENT_LENGTH: %d", content_len, MAX_CONTENT_LENGTH); body = IOBuf_read_all(conn->iob, content_len, CLIENT_READ_RETRIES); check(body != NULL, "Client closed the connection during upload."); rc = Connection_send_to_handler(conn, handler, body, content_len); check_debug(rc == 0, "Failed to deliver to the handler."); } Log_request(conn, 200, content_len); return REQ_SENT; error: return CLOSE; }