static struct HTTPRequest *read_request(FILE *in) { struct HTTPRequest *req; struct HTTPHeaderField *h; req = xmalloc(sizeof(struct HTTPRequest)); read_request_line(req, in); req->header = NULL; while (h = read_header_field(in)) { h->next = req->header; req->header = h; } req->length = content_length(req); if (req->length != 0) { if (req->length > MAX_REQUEST_BODY_LENGTH) { log_exit("request body too long"); } req->body = xmalloc(req->length); if (fread(req->body, req->length, 1, in) < 1) { log_exit("failed to read request body"); } } else { req->body = NULL; } return req; }
int main() { FILE *fin; char first_line[BUF_MAX_LEN]; fin = stdin; if (fgets(first_line, BUF_MAX_LEN, fin) == NULL) { perror("fgets"); return 1; } struct http_request_header *req; req = read_request_line(first_line); printf("=== result ===\n"); printf("method:%s\n", req->method); printf("path:%s\n", req->path); printf("proto:%s\n", req->proto); free(req->method); free(req->path); free(req->proto); free(req); return 0; }
std::unique_ptr<http::request> http::request_reader::accept_request() { std::string method; std::string request_uri; std::tie(method, request_uri) = read_request_line(); auto headers = read_request_headers(); return std::unique_ptr<http::request>(new http::request(method, request_uri, headers)); }
/*************************** read_request リクエストのread ***************************/ HttpRequest* read_request( FILE *in ) { HttpRequest *req; HttpHeaderField *h; int ret = 0; req = xmalloc(sizeof(HttpRequest)); read_request_line(req, in); req->header = NULL; while(NULL != (h = read_header_field(in))) { h->next = req->header; req->header = h; } req->length = content_length(req); if(req->length != 0) { if(req->length != MAX_REQUEST_BODY_LENGTH) { log_exit("request body too long"); } req->body = xmalloc(req->length); ret = fread(req->body, req->length, 1, in); if(ret < 1) { log_exit("failed to read request body"); } else { req->body = NULL; } } return req; }
bool http_connection::loop(unsigned fd) { socket_wrapper::io_vector io_vector[2]; size_t total = 0; size_t count; bool ret; do { logger::instance().log(logger::LOG_DEBUG, "[http_connection::loop] (fd %d) State = %s.", fd, state_to_string(_M_state)); switch (_M_state) { case BEGIN_REQUEST_STATE: if ((!_M_readable) && (_M_inp == (off_t) _M_in.count())) { return true; } if (!read_request_line(fd, total)) { return false; } break; case READING_HEADERS_STATE: if (!_M_readable) { return true; } if (!read_headers(fd, total)) { return false; } break; case PROCESSING_REQUEST_STATE: if (!process_request(fd)) { return false; } if (_M_error != http_error::OK) { total = 0; _M_state = PREPARING_ERROR_PAGE_STATE; } else { if ((_M_state != PREPARING_HTTP_REQUEST_STATE) && (_M_state != READING_BODY_STATE) && (_M_state != READING_CHUNKED_BODY_STATE)) { if (!modify(fd, tcp_server::WRITE)) { return false; } total = 0; } } break; case READING_BODY_STATE: if (!_M_readable) { return true; } if (!read_body(fd, total)) { return false; } break; case READING_CHUNKED_BODY_STATE: if (!_M_readable) { return true; } if (!read_chunked_body(fd, total)) { return false; } break; case PREPARING_HTTP_REQUEST_STATE: if (!prepare_http_request(fd)) { _M_state = PREPARING_ERROR_PAGE_STATE; } else { _M_state = WAITING_FOR_BACKEND_STATE; } break; case WAITING_FOR_BACKEND_STATE: return true; case PREPARING_ERROR_PAGE_STATE: if ((!prepare_error_page()) || (!modify(fd, tcp_server::WRITE))) { return false; } break; case SENDING_TWO_BUFFERS_STATE: if (!_M_writable) { return true; } io_vector[0].iov_base = _M_out.data(); io_vector[0].iov_len = _M_out.count(); io_vector[1].iov_base = _M_bodyp->data(); io_vector[1].iov_len = _M_bodyp->count(); if (!writev(fd, io_vector, 2, total)) { return false; } else if (_M_outp == (off_t) (_M_out.count() + _M_bodyp->count())) { _M_state = REQUEST_COMPLETED_STATE; } break; case SENDING_HEADERS_STATE: if (!_M_writable) { return true; } if (!write(fd, total)) { return false; } else if (_M_outp == (off_t) _M_out.count()) { if (_M_method == http_method::HEAD) { _M_state = REQUEST_COMPLETED_STATE; } else if (_M_error != http_error::OK) { _M_state = REQUEST_COMPLETED_STATE; } else if (_M_filesize == 0) { _M_state = REQUEST_COMPLETED_STATE; } else { if (_M_ranges.count() == 0) { _M_outp = 0; } else { const range_list::range* range = _M_ranges.get(0); _M_outp = range->from; } _M_state = SENDING_BODY_STATE; } } break; case SENDING_BODY_STATE: if (!_M_writable) { return true; } if (!sendfile(fd, _M_fd, _M_filesize, &_M_ranges, _M_nrange, total)) { return false; } else { size_t nranges = _M_ranges.count(); if (nranges == 0) { if (_M_outp == _M_filesize) { socket_wrapper::uncork(fd); _M_state = REQUEST_COMPLETED_STATE; } } else { const range_list::range* range = _M_ranges.get(_M_nrange); if (_M_outp == range->to + 1) { if (nranges == 1) { socket_wrapper::uncork(fd); _M_state = REQUEST_COMPLETED_STATE; } else { _M_out.reset(); // Last part? if (++_M_nrange == nranges) { if (!_M_out.format("\r\n--%0*u--\r\n", http_headers::BOUNDARY_WIDTH, _M_boundary)) { return false; } _M_state = SENDING_MULTIPART_FOOTER_STATE; } else { if (!build_part_header()) { return false; } _M_state = SENDING_PART_HEADER_STATE; } _M_outp = 0; } } } } break; case SENDING_PART_HEADER_STATE: if (!_M_writable) { return true; } if (!write(fd, total)) { return false; } else if (_M_outp == (off_t) _M_out.count()) { const range_list::range* range = _M_ranges.get(_M_nrange); _M_outp = range->from; _M_state = SENDING_BODY_STATE; } break; case SENDING_MULTIPART_FOOTER_STATE: if (!_M_writable) { return true; } if (!write(fd, total)) { return false; } else if (_M_outp == (off_t) _M_out.count()) { socket_wrapper::uncork(fd); _M_state = REQUEST_COMPLETED_STATE; } break; case SENDING_BACKEND_HEADERS_STATE: if (!_M_writable) { return true; } if ((!_M_payload_in_memory) || (_M_filesize == 0) || (_M_method == http_method::HEAD)) { count = _M_out.count(); ret = write(fd, total); } else { io_vector[0].iov_base = _M_out.data(); io_vector[0].iov_len = _M_out.count(); if (_M_error == http_error::OK) { io_vector[1].iov_base = _M_body.data() + _M_backend_response_header_size; } else { io_vector[1].iov_base = _M_bodyp->data(); } io_vector[1].iov_len = _M_filesize; count = io_vector[0].iov_len + io_vector[1].iov_len; ret = writev(fd, io_vector, 2, total); } if (!ret) { return false; } else if (_M_outp == (off_t) count) { if (_M_payload_in_memory) { _M_state = REQUEST_COMPLETED_STATE; } else { _M_outp = 0; _M_state = SENDING_BACKEND_BODY_STATE; } } break; case SENDING_BACKEND_BODY_STATE: if (!_M_writable) { return true; } if (!sendfile(fd, _M_tmpfile, _M_filesize, total)) { return false; } else if (_M_outp == _M_filesize) { socket_wrapper::uncork(fd); _M_state = REQUEST_COMPLETED_STATE; } break; case REQUEST_COMPLETED_STATE: if ((_M_vhost) && (_M_vhost->log_requests)) { _M_vhost->log->log(*this, fd); } // Close connection? if (!_M_keep_alive) { return false; } else { if (!modify(fd, tcp_server::READ)) { return false; } reset(); // If there is more data in the input buffer... size_t left = _M_in.count() - _M_inp; if (left > 0) { // Move data at the beginning of the buffer. char* data = _M_in.data(); memmove(data, data + _M_inp, left); _M_in.set_count(left); } else { _M_in.reset(); } _M_inp = 0; } break; } } while (!_M_in_ready_list); return true; }
/* * This is the main drive for each connection. As you can tell, for the * first few steps we are using a blocking socket. If you remember the * older tinyproxy code, this use to be a very confusing state machine. * Well, no more! :) The sockets are only switched into nonblocking mode * when we start the relay portion. This makes most of the original * tinyproxy code, which was confusing, redundant. Hail progress. * - rjkaes */ void handle_connection(int fd) { struct conn_s *connptr; struct request_s *request = NULL; hashmap_t hashofheaders = NULL; char peer_ipaddr[PEER_IP_LENGTH]; char peer_string[PEER_STRING_LENGTH]; getpeer_information(fd, peer_ipaddr, peer_string); log_message(LOG_CONN, "Connect (file descriptor %d): %s [%s]", fd, peer_string, peer_ipaddr); connptr = initialize_conn(fd, peer_ipaddr, peer_string); if (!connptr) { close(fd); return; } if (check_acl(fd, peer_ipaddr, peer_string) <= 0) { update_stats(STAT_DENIED); indicate_http_error(connptr, 403, "Access denied", "detail", "The administrator of this proxy has not configured it to service requests from your host.", NULL); send_http_error_message(connptr); destroy_conn(connptr); return; } if (read_request_line(connptr) < 0) { update_stats(STAT_BADCONN); indicate_http_error(connptr, 408, "Timeout", "detail", "Server timeout waiting for the HTTP request from the client.", NULL); send_http_error_message(connptr); destroy_conn(connptr); return; } /* * The "hashofheaders" store the client's headers. */ if (!(hashofheaders = hashmap_create(HEADER_BUCKETS))) { update_stats(STAT_BADCONN); indicate_http_error(connptr, 503, "Internal error", "detail", "An internal server error occurred while processing your request. Please contact the administrator.", NULL); send_http_error_message(connptr); destroy_conn(connptr); return; } /* * Get all the headers from the client in a big hash. */ if (get_all_headers(connptr->client_fd, hashofheaders) < 0) { log_message(LOG_WARNING, "Could not retrieve all the headers from the client"); hashmap_delete(hashofheaders); update_stats(STAT_BADCONN); destroy_conn(connptr); return; } request = process_request(connptr, hashofheaders); if (!request) { if (!connptr->error_variables && !connptr->show_stats) { update_stats(STAT_BADCONN); destroy_conn(connptr); hashmap_delete(hashofheaders); return; } goto send_error; } connptr->upstream_proxy = UPSTREAM_HOST(request->host); if (connptr->upstream_proxy != NULL) { if (connect_to_upstream(connptr, request) < 0) { goto send_error; } } else { connptr->server_fd = opensock(request->host, request->port); if (connptr->server_fd < 0) { indicate_http_error(connptr, 500, "Unable to connect", "detail", PACKAGE " was unable to connect to the remote web server.", "error", strerror(errno), NULL); goto send_error; } log_message(LOG_CONN, "Established connection to host \"%s\" using file descriptor %d.", request->host, connptr->server_fd); if (!connptr->connect_method) establish_http_connection(connptr, request); } send_error: free_request_struct(request); if (process_client_headers(connptr, hashofheaders) < 0) { update_stats(STAT_BADCONN); if (!connptr->error_variables) { hashmap_delete(hashofheaders); destroy_conn(connptr); return; } } hashmap_delete(hashofheaders); if (connptr->error_variables) { send_http_error_message(connptr); destroy_conn(connptr); return; } else if (connptr->show_stats) { showstats(connptr); destroy_conn(connptr); return; } if (!connptr->connect_method || (connptr->upstream_proxy != NULL)) { if (process_server_headers(connptr) < 0) { if (connptr->error_variables) send_http_error_message(connptr); update_stats(STAT_BADCONN); destroy_conn(connptr); return; } } else { if (send_ssl_response(connptr) < 0) { log_message(LOG_ERR, "handle_connection: Could not send SSL greeting to client."); update_stats(STAT_BADCONN); destroy_conn(connptr); return; } } relay_connection(connptr); log_message(LOG_INFO, "Closed connection between local client (fd:%d) and remote client (fd:%d)", connptr->client_fd, connptr->server_fd); /* * All done... close everything and go home... :) */ destroy_conn(connptr); return; }