int match(const char * pload,int len,char ** source_path) { const char* method; size_t method_len; const char* path; size_t path_len; int minor_version; struct phr_header headers[HEADER_NUM]; size_t num_headers = sizeof(headers) / sizeof(headers[0]); int re =phr_parse_request(pload,len, &method, &method_len, &path,&path_len, &minor_version, headers,&num_headers,0); printf("~~~~%d~~~\n",re ); if(re<=0) return FALSE; // find_host int i; for(i=0;i<num_headers;i++) { if (memcmp(headers[i].name,"Host",headers[i].name_len)==0) { int index = check_ini(headers[i].value,headers[i].value_len,path,path_len); if(index!=-1) { *source_path = soft_array[index].source; return TRUE; } } } return FALSE; }
// returns 1 on successful parsing, 0 on parsing incomplete, -1 on connection close static int read_request(struct cs_io *cs_w) { const char *method, *path; int minor_version; struct phr_header headers[100]; size_t method_len, path_len, num_headers; int pret; ssize_t rret; /* read the request */ rret = recv(cs_w->io.fd, cs_w->buf + cs_w->len, sizeof cs_w->buf - cs_w->len, MSG_DONTWAIT); if (rret < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return 0; die("recv"); } if (rret == 0) { fprintf(stderr, "connection closed by peer, len = %d\n", sizeof cs_w->buf - cs_w->len); fflush(stderr); return -1; } cs_w->last_len = cs_w->len; cs_w->len += rret; num_headers = sizeof headers / sizeof headers[0]; /* parse the request */ pret = phr_parse_request( cs_w->buf, cs_w->len, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, cs_w->last_len ); // puts("finished parsing"); if (pret > 0) { /* successfully parsed the request */ cs_w->len = pret; setup_response(cs_w); // printf("response was setup: %d\n", cs_w->response_len); return 1; } if (pret == -1) { puts("parse error"); exit(EXIT_FAILURE); } /* request is incomplete, continue the loop */ assert(pret == -2); if (cs_w->len == sizeof cs_w->buf) { puts("request is too long"); exit(EXIT_FAILURE); } return 0; }
static void read_cb(picoev_loop* loop, int fd, int revents, void* cb_arg) { char buf[16384]; const char* method, * path; size_t method_len, path_len, num_headers; int minor_version, r; struct phr_header headers[128]; /* read request */ assert((revents & PICOEV_READ) != 0); r = read(fd, buf, sizeof(buf)); if (r == 0) { goto CLOSE; } else if (r == -1) { if (errno == EINTR || errno == EAGAIN) { return; } goto CLOSE; } /* parse request, should arrive in one packat :-p */ num_headers = sizeof(headers) / sizeof(headers[0]); r = phr_parse_request(buf, r, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, 0); assert(r > 0); #define RES "HTTP\1.0 200 OK\r\n" \ "Connection: keep-alive\r\n" \ "Content-Length: 13\r\n" \ "Content-Type: text/plain\r\n" \ "\r\n" \ "hello world!\n" r = write(fd, RES, sizeof(RES) - 1); assert(r == sizeof(RES) - 1); #undef RES return; CLOSE: picoev_del(loop, fd); close(fd); }
static void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { if (nread < 0) { if (buf->base) free(buf->base); /* FIXME uv_shutdown_t* shutdown_req = (uv_shutdown_t*) malloc(sizeof(uv_shutdown_t)); if (shutdown_req == NULL) { fprintf(stderr, "Allocate error\n"); uv_close((uv_handle_t*) stream, on_close); return; } uv_shutdown(shutdown_req, stream, on_shutdown); */ uv_close((uv_handle_t*) stream, on_close); return; } if (nread == 0) { free(buf->base); return; } http_request* request = calloc(1, sizeof(http_request)); if (request == NULL) { free(buf->base); fprintf(stderr, "Allocate error: %s\n", strerror(errno)); uv_close((uv_handle_t*) stream, on_close); return; } stream->data = request; request->handle = (uv_handle_t*) stream; request->num_headers = sizeof(request->headers) / sizeof(request->headers[0]); int nparsed = phr_parse_request( buf->base, buf->len, &request->method, &request->method_len, &request->path, &request->path_len, &request->minor_version, request->headers, &request->num_headers, 0); if (nparsed < 0) { free(request); free(buf->base); fprintf(stderr, "Invalid request\n"); uv_close((uv_handle_t*) stream, on_close); return; } /* int cl = content_length(request); if (cl >= 0 && cl < buf->len - nparsed) { free(request); free(buf->base); return; } */ /* TODO: handle reading whole payload */ request->payload = buf->base + nparsed; request->payload_len = buf->len - nparsed; request_complete(request); free(buf->base); }
static void handle_incoming_request(struct st_h2o_http1_conn_t *conn) { size_t inreqlen = conn->sock->input->size < H2O_MAX_REQLEN ? conn->sock->input->size : H2O_MAX_REQLEN; int reqlen, minor_version; struct phr_header headers[H2O_MAX_HEADERS]; size_t num_headers = H2O_MAX_HEADERS; ssize_t entity_body_header_index; h2o_iovec_t expect; /* need to set request_begin_at here for keep-alive connection */ if (conn->req.timestamps.request_begin_at.tv_sec == 0) conn->req.timestamps.request_begin_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); reqlen = phr_parse_request(conn->sock->input->bytes, inreqlen, (const char **)&conn->req.input.method.base, &conn->req.input.method.len, (const char **)&conn->req.input.path.base, &conn->req.input.path.len, &minor_version, headers, &num_headers, conn->_prevreqlen); conn->_prevreqlen = inreqlen; switch (reqlen) { default: // parse complete conn->_reqsize = reqlen; if ((entity_body_header_index = fixup_request(conn, headers, num_headers, minor_version, &expect)) != -1) { conn->req.timestamps.request_body_begin_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); if (expect.base != NULL) { if (!h2o_lcstris(expect.base, expect.len, H2O_STRLIT("100-continue"))) { set_timeout(conn, NULL, NULL); h2o_socket_read_stop(conn->sock); h2o_send_error(&conn->req, 417, "Expectation Failed", "unknown expectation", H2O_SEND_ERROR_HTTP1_CLOSE_CONNECTION); return; } static const h2o_iovec_t res = {H2O_STRLIT("HTTP/1.1 100 Continue\r\n\r\n")}; h2o_socket_write(conn->sock, (void *)&res, 1, on_continue_sent); } if (create_entity_reader(conn, headers + entity_body_header_index) != 0) { return; } if (expect.base != NULL) { /* processing of the incoming entity is postponed until the 100 response is sent */ h2o_socket_read_stop(conn->sock); return; } conn->_req_entity_reader->handle_incoming_entity(conn); } else { set_timeout(conn, NULL, NULL); h2o_socket_read_stop(conn->sock); process_request(conn); } return; case -2: // incomplete if (inreqlen == H2O_MAX_REQLEN) { // request is too long (TODO notify) close_connection(conn, 1); } return; case -1: // error /* upgrade to HTTP/2 if the request starts with: PRI * HTTP/2 */ if (conn->super.ctx->globalconf->http1.upgrade_to_http2) { /* should check up to the first octet that phr_parse_request returns an error */ static const h2o_iovec_t HTTP2_SIG = {H2O_STRLIT("PRI * HTTP/2")}; if (conn->sock->input->size >= HTTP2_SIG.len && memcmp(conn->sock->input->bytes, HTTP2_SIG.base, HTTP2_SIG.len) == 0) { h2o_accept_ctx_t accept_ctx = {conn->super.ctx, conn->super.hosts}; h2o_socket_t *sock = conn->sock; struct timeval connected_at = conn->super.connected_at; /* destruct the connection after detatching the socket */ conn->sock = NULL; close_connection(conn, 1); /* and accept as http2 connection */ h2o_http2_accept(&accept_ctx, sock, connected_at); return; } } close_connection(conn, 1); return; } }
static int _parse_http_request(char *buf, ssize_t buf_len, VALUE env) { const char* method; size_t method_len; const char* path; size_t path_len; int minor_version; struct phr_header headers[MAX_HEADERS]; size_t num_headers, question_at; size_t i; int ret; char tmp[MAX_HEADER_NAME_LEN + sizeof("HTTP_") - 1]; VALUE last_value; num_headers = MAX_HEADERS; ret = phr_parse_request(buf, buf_len, &method, &method_len, &path, &path_len, &minor_version, headers, &num_headers, 0); if (ret < 0) goto done; rb_hash_aset(env, request_method_key, rb_str_new(method,method_len)); rb_hash_aset(env, request_uri_key, rb_str_new(path, path_len)); rb_hash_aset(env, script_name_key, rb_str_new2("")); strcpy(tmp, "HTTP/1."); tmp[7] = 48 + ((minor_version > 1 || minor_version < 0 ) ? 0 : minor_version); rb_hash_aset(env, server_protocol_key, rb_str_new(tmp, sizeof("HTTP/1.0") - 1)); /* PATH_INFO QUERY_STRING */ path_len = find_ch(path, path_len, '#'); /* strip off all text after # after storing request_uri */ question_at = find_ch(path, path_len, '?'); if ( store_path_info(env, path, question_at) < 0 ) { rb_hash_clear(env); ret = -1; goto done; } if (question_at != path_len) ++question_at; rb_hash_aset(env, query_string_key, rb_str_new(path + question_at, path_len - question_at)); last_value = Qnil; for (i = 0; i < num_headers; ++i) { if (headers[i].name != NULL) { const char* name; size_t name_len; VALUE slot; VALUE env_key; env_key = find_common_header(headers + i); if ( env_key == Qnil ) { const char* s; char* d; size_t n; if (sizeof(tmp) - 5 < headers[i].name_len) { rb_hash_clear(env); ret = -1; goto done; } strcpy(tmp, "HTTP_"); for (s = headers[i].name, n = headers[i].name_len, d = tmp + 5; n != 0; s++, --n, d++) { *d = *s == '-' ? '_' : TOU(*s); name = tmp; name_len = headers[i].name_len + 5; env_key = rb_str_new(name, name_len); } } slot = rb_hash_aref(env, env_key); if ( slot != Qnil ) { rb_str_cat2(slot, ", "); rb_str_cat(slot, headers[i].value, headers[i].value_len); } else { slot = rb_str_new(headers[i].value, headers[i].value_len); rb_hash_aset(env, env_key, slot); last_value = slot; } } else { /* continuing lines of a mulitiline header */ if ( last_value != Qnil ) rb_str_cat(last_value, headers[i].value, headers[i].value_len); } } done: return ret; }