int connection_proxy_req_parse(Connection *conn) { int rc = 0; Host *target_host = conn->req->target_host; Backend *req_action = conn->req->action; check_debug(!IOBuf_closed(conn->iob), "Client closed, goodbye."); rc = Connection_read_header(conn, conn->req); check_debug(rc > 0, "Failed to read another header."); error_unless(Request_is_http(conn->req), conn, 400, "Someone tried to change the protocol on us from HTTP."); Backend *found = Host_match_backend(target_host, Request_path(conn->req), NULL); error_unless(found, conn, 404, "Handler not found: %s", bdata(Request_path(conn->req))); // break out of PROXY if the actions don't match if(found != req_action) { Request_set_action(conn->req, found); return Connection_backend_event(found, conn); } else { return HTTP_REQ; } error_response(conn, 500, "Invalid code branch, tell Zed."); error: return REMOTE_CLOSE; }
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_route_request(Connection *conn) { Host *host = NULL; Route *route = NULL; bstring path = Request_path(conn->req); if(conn->req->host_name) { host = Server_match_backend(conn->server, conn->req->host_name); } else { host = conn->server->default_host; } error_unless(host, conn, 404, "Request for a host we don't have registered: %s", bdata(conn->req->host_name)); Backend *found = Host_match_backend(host, path, &route); error_unless(found, conn, 404, "Handler not found: %s", bdata(path)); Request_set_action(conn->req, found); conn->req->target_host = host; conn->req->pattern = route->pattern; conn->req->prefix = route->prefix; return Connection_backend_event(found, conn); error: return CLOSE; }
int connection_route_request(Connection *conn) { Host *host = NULL; Route *route = NULL; bstring path = Request_path(conn->req); check_debug(path != NULL, "No path given, in request, ignoring."); Server *server = Server_queue_latest(); check(server != NULL, "No server in the server queue, tell Zed."); if(conn->req->host_name) { host = Server_match_backend(server, conn->req->host_name); } else { host = server->default_host; } error_unless(host, conn, 404, "Request for a host we don't have registered: %s", bdata(conn->req->host_name)); Backend *found = Host_match_backend(host, path, &route); error_unless(found, conn, 404, "Handler not found: %s", bdata(path)); Request_set_action(conn->req, found); conn->req->target_host = host; conn->req->pattern = route->pattern; conn->req->prefix = route->prefix; return Connection_backend_event(found, conn); error: return CLOSE; }
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_identify_request(Connection *conn) { int next = CLOSE; if(Request_is_xml(conn->req)) { if(biseq(Request_path(conn->req), &POLICY_XML_REQUEST)) { debug("XML POLICY CONNECTION: %s", bdata(Request_path(conn->req))); conn->type = CONN_TYPE_SOCKET; taskname("XML"); next = SOCKET_REQ; } else { debug("XML MESSAGE"); conn->type = CONN_TYPE_MSG; taskname("MSG"); next = MSG_REQ; } } else if(Request_is_json(conn->req)) { debug("JSON SOCKET MESSAGE"); conn->type = CONN_TYPE_MSG; taskname("MSG"); next = MSG_REQ; } else if(Request_is_websocket(conn->req)) { debug("WEBSOCKET MESSAGE"); conn->type = CONN_TYPE_SOCKET; taskname("WS"); next = WS_REQ; } else if(Request_is_http(conn->req)) { debug("HTTP MESSAGE"); conn->type = CONN_TYPE_HTTP; taskname("HTTP"); next = HTTP_REQ; } else { error_response(conn, 500, "Invalid code branch, tell Zed."); } return next; error: return CLOSE; }
int Connection_send_to_handler(Connection *conn, Handler *handler, char *body, int content_len) { int rc = 0; bstring payload = NULL; if(conn->iob->use_ssl) Connection_fingerprint_from_cert(conn); error_unless(handler->running, conn, 404, "Handler shutdown while trying to deliver: %s", bdata(Request_path(conn->req))); if(handler->protocol == HANDLER_PROTO_TNET) { payload = Request_to_tnetstring(conn->req, handler->send_ident, IOBuf_fd(conn->iob), body, content_len); } else if(handler->protocol == HANDLER_PROTO_JSON) { payload = Request_to_payload(conn->req, handler->send_ident, IOBuf_fd(conn->iob), body, content_len); } else { sentinel("Invalid protocol type: %d", handler->protocol); } check(payload, "Failed to create payload for request."); debug("HTTP TO HANDLER: %.*s", blength(payload) - content_len, bdata(payload)); rc = Handler_deliver(handler->send_socket, bdata(payload), blength(payload)); free(payload); payload = NULL; error_unless(rc != -1, conn, 502, "Failed to deliver to handler: %s", bdata(Request_path(conn->req))); return 0; error: if(payload) free(payload); return -1; }
static inline bstring make_log_message(Request *req, const char *remote_addr, int remote_port, int status, int size) { bstring request_method = NULL; if (Request_is_json(req)) { request_method = &JSON_METHOD; } else if (Request_is_xml(req)) { request_method = &XML_METHOD; } else { request_method = req->request_method; } tns_outbuf outbuf = {.buffer = NULL}; bstring b_temp; check(tns_render_log_start(&outbuf), "Could not initialize buffer"); tns_render_number_prepend(&outbuf, size); tns_render_number_prepend(&outbuf, status); b_temp = bfromcstr(Request_is_json(req) ? "" : bdata(req->version)); tns_render_string_prepend(&outbuf, b_temp); bdestroy(b_temp); tns_render_string_prepend(&outbuf, Request_path(req)); tns_render_string_prepend(&outbuf, request_method); tns_render_number_prepend(&outbuf, (int) time(NULL)); tns_render_number_prepend(&outbuf, remote_port); b_temp = bfromcstr(remote_addr); tns_render_string_prepend(&outbuf, b_temp); bdestroy(b_temp); tns_render_string_prepend(&outbuf, req->target_host->name); tns_render_log_end(&outbuf); // log_data now owns the outbuf buffer bstring log_data = tns_outbuf_to_bstring(&outbuf); bconchar(log_data, '\n'); return log_data; error: return NULL; }
int Dir_serve_file(Dir *dir, Request *req, Connection *conn) { FileRecord *file = NULL; bstring resp = NULL; bstring path = Request_path(req); bstring pattern = req->pattern; int rc = 0; int is_get = biseq(req->request_method, &HTTP_GET); int is_head = is_get ? 0 : biseq(req->request_method, &HTTP_HEAD); check(path, "Request had not path. That's weird."); req->response_size = 0; if(!(is_get || is_head)) { req->status_code = 405; rc = Response_send_status(conn, &HTTP_405); check_debug(rc == blength(&HTTP_405), "Failed to send 405 to client."); return -1; } else { file = Dir_resolve_file(dir, pattern, path); resp = Dir_calculate_response(req, file); if(resp) { rc = Response_send_status(conn, resp); check_debug(rc == blength(resp), "Failed to send error response on file serving."); } else if(is_get) { rc = Dir_stream_file(file, conn); req->response_size = rc; check_debug(rc == file->sb.st_size, "Didn't send all of the file, sent %d of %s.", rc, bdata(path)); } else if(is_head) { rc = Dir_send_header(file, conn); check_debug(rc, "Failed to write header to socket."); } else { sentinel("How the hell did you get to here. Tell Zed."); } FileRecord_release(file); return 0; } sentinel("Invalid code branch, Tell Zed you have magic."); error: FileRecord_release(file); return -1; }
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_send_to_handler(Connection *conn, Handler *handler, char *body, int content_len) { int rc = 0; bstring result = NULL; result = Request_to_payload(conn->req, handler->send_ident, IOBuf_fd(conn->iob), body, content_len); check(result, "Failed to create payload for request."); debug("HTTP TO HANDLER: %.*s", blength(result) - content_len, bdata(result)); rc = Handler_deliver(handler->send_socket, bdata(result), blength(result)); error_unless(rc != -1, conn, 502, "Failed to deliver to handler: %s", bdata(Request_path(conn->req))); bdestroy(result); return 0; error: bdestroy(result); return -1; }
static inline int ident_and_register(Connection *conn, int reg_too) { int next = CLOSE; if(Request_is_xml(conn->req)) { if(biseq(Request_path(conn->req), &POLICY_XML_REQUEST)) { debug("XML POLICY CONNECTION"); conn->type = CONN_TYPE_SOCKET; taskname("XML"); next = SOCKET_REQ; } else { debug("XML MESSAGE"); conn->type = CONN_TYPE_MSG; taskname("MSG"); next = MSG_REQ; } } else if(Request_is_json(conn->req)) { debug("JSON SOCKET MESSAGE"); conn->type = CONN_TYPE_MSG; taskname("MSG"); next = MSG_REQ; } else if(Request_is_http(conn->req)) { debug("HTTP MESSAGE"); conn->type = CONN_TYPE_HTTP; taskname("HTTP"); next = HTTP_REQ; } else { error_response(conn, 500, "Invalid code branch, tell Zed."); } if(reg_too) Register_connect(IOBuf_fd(conn->iob), (void*)conn); return next; 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; }