/* Responsible for reading the request * * if returns >= 0 : the connection will be released * * if returns < 0 : the connection will be released as BAD / broken */ static int wss_read_req(struct tcp_connection* con, int* bytes_read) { int size; /* we need to fix the SSL connection before doing anything */ if (tls_fix_read_conn(con) < 0) { LM_ERR("cannot fix read connection\n"); goto error; } if (WS_STATE(con) != WS_CON_HANDSHAKE_DONE) { size = ws_server_handshake(con); if (size < 0) { LM_ERR("cannot complete WebSocket handshake\n"); goto error; } if (size == 0) goto done; } if (WS_STATE(con) == WS_CON_HANDSHAKE_DONE && ws_process(con) < 0) goto error; done: return 0; error: /* connection will be released as ERROR */ return -1; }
/* Responsible for reading the request * * if returns >= 0 : the connection will be released * * if returns < 0 : the connection will be released as BAD / broken */ static int ws_read_req(struct tcp_connection* con, int* bytes_read) { int size; if (WS_STATE(con) != WS_CON_HANDSHAKE_DONE) { size = ws_server_handshake(con); if (size < 0) { LM_ERR("cannot complete WebSocket handshake\n"); goto error; } if (size == 0) goto done; } if (WS_STATE(con) == WS_CON_HANDSHAKE_DONE && ws_process(con) < 0) goto error; done: return 0; error: /* connection will be released as ERROR */ return -1; }
void *http_process(void *args) { int32 fd; struct http_request *req; int8 *cp = NULL; int8 *line = NULL; int8 *method = NULL; int8 *url = NULL; int8 *protocol = NULL; struct timeval timo; int32 optval = 1; int32 rc, rc_r, rc_s; int32 r = 0; if (NULL == args) return NULL; req = (struct http_request *)args; fd = req->fd; req->buff = malloc(BUFFSIZ); req->buff_size = BUFFSIZ; if (NULL == req->buff) { HTTPD_ERR("get_request_line malloc %d fail\n", BUFFSIZ); free(args); return NULL; } memset(req->buff, 0, BUFFSIZ); rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); if (rc < 0) HTTPD_ERR("setsockopt error rc=%d errno=%d %s\n", rc, errno, strerror(errno)); timo.tv_sec = HTTPD_TIMO; timo.tv_usec = 0; rc_r = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timo, sizeof(timo)); rc_s = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timo, sizeof(timo)); if (rc_r < 0 || rc_s < 0) HTTPD_ERR("setsockopt error fd=%d rc=%d rc_r=%d rc_s=%d errno=%d %s\n", fd, rc, rc_r, rc_s, errno, strerror(errno)); /* GET / HTTP/1.1 */ method = get_request_line(req); if (method == NULL) goto close_task; url = parse_reqline(fd, method); if (url == NULL) goto close_task; protocol = parse_reqline(fd, url); if (protocol == NULL) goto close_task; req->method = http_method(method); if (req->method == M_OPTIONS) { send_error(fd, 204, "No Content", NULL, "Method OPTIONS."); goto close_task; } if (req->method == M_UNKNOWN) { send_error(fd, 400, "Bad Request", NULL, "Method Not Support."); goto close_task; } decode_url(req, url); HTTPD_INFO("method[%s] protocol[%s] url[%s] path[%s] query[%s]!\n", method, protocol, url, req->path, req->query ? : ""); while ((line = get_request_line(req)) != NULL) { if (line[0] == '\0') break; if (strncasecmp(line, "Upgrade:", 8) == 0) { cp = &line[8]; cp += strspn(cp, " \t"); if (strncasecmp(cp, "websocket", 9) == 0) req->is_websocket = 1; } else if (strncasecmp(line, "Connection:", 11) == 0) { cp = &line[11]; cp += strspn(cp, " \t"); /* Firefox: [Connection: keep-alive, Upgrade] */ if (strcasestr(cp, "Upgrade") != NULL) req->is_connection_upgrade = 1; } else if (strncasecmp(line, "Sec-WebSocket-Key:", 18) == 0) { cp = &line[18]; cp += strspn(cp, " \t"); req->sec_websocket_key = cp; } else if (strncasecmp(line, "Origin:", 7) == 0) { cp = &line[7]; cp += strspn(cp, " \t"); req->origin = cp; } else if (strncasecmp(line, "Sec-WebSocket-Version:", 22) == 0) { cp = &line[22]; cp += strspn(cp, " \t"); req->sec_websocket_version = atoi(cp); } else if (strncasecmp(line, "Content-Length:", 15) == 0) { cp = &line[15]; cp += strspn(cp, " \t"); req->content_length = atol(cp); if ((BUFFSIZ < req->content_length + MAX_HEADER_LEN) && (req->buff_size != req->content_length + MAX_HEADER_LEN) + 1) { re_alloc_buff(req); memset(req->buff + BUFFSIZ, 0, req->buff_size - BUFFSIZ); } } else if (strncasecmp(line, "Content-Type:", 13) == 0) { cp = &line[13]; cp += strspn(cp, " \t"); req->content_type = cp; } else if (strncasecmp(line, "Host:", 5) == 0) { cp = &line[5]; cp += strspn(cp, " \t"); req->host = cp; } } HTTPD_INFO("Left %d bytes HTTP data with Content-Length: %ld req->sz[%d] req->pos[%d]\n", req->sz - req->pos, req->content_length, req->sz, req->pos); if (line == NULL || req->path[0] != '/') send_error(fd, 400, "Bad Request", NULL, "Bad Request!"); if ((0 != req->content_length) && (req->sz != req->hd_sz + req->content_length)) { while ((r = http_read(req->fd, req->buff + req->sz, req->buff_size - req->sz)) > 0) { req->sz += r; if (req->sz == req->hd_sz + req->content_length) break; } } if (req->is_websocket) ws_process(req); else { uint32 i = 0; int8 *file = NULL; int8 *path = req->path; int8 *pTmp = path; int8 prefix[PREFIX_LEN] = {0}; int8 new_link[MAX_URL + 8] = {0}; rmm_cfg_get_rest_prefix(prefix, PREFIX_LEN); /*snprintf(new_link, (MAX_URL + 8), "%s%s", prefix, "/rack");*/ snprintf_s_s(new_link, (MAX_URL + 8), "%s", prefix); /*TODO: move to correct place */ get_json_pointer(req); /* remove redundant '/' */ for (; *(path+i) != '\0'; i++) { if ((*(path+i) == '/') && (*(path+i+1) == '/')) continue; *pTmp++ = *(path+i); } *pTmp = '\0'; if ((path[1] == '\0') || (strncasecmp(path, new_link, strnlen_s(new_link, sizeof(new_link)-1)) == 0)) file = NULL; else file = path; if (file != NULL) send_file(req->fd, file); else rest_process(req); } close_task: close(fd); if (NULL != req->buff) { free(req->buff); req->buff = NULL; } HTTPD_INFO("\nrest_req_thread[%lld] exit, fd[%d], errno:%d %s\n", (uint64)(req->tid_rest_req), fd, errno, strerror(errno)); free(args); pthread_detach(pthread_self()); return NULL; }
/* Responsible for reading the request * * if returns >= 0 : the connection will be released * * if returns < 0 : the connection will be released as BAD / broken */ static int wss_read_req(struct tcp_connection* con, int* bytes_read) { int size; struct ws_data* d; /* we need to fix the SSL connection before doing anything */ if (tls_fix_read_conn(con) < 0) { LM_ERR("cannot fix read connection\n"); if ( (d=con->proto_data) && d->dest && d->tprot ) { if ( d->message ) { send_trace_message( d->message, t_dst); d->message = NULL; /* don't allow future traces for this connection */ d->tprot = 0; d->dest = 0; } } goto error; } d=con->proto_data; if (WS_STATE(con) != WS_CON_HANDSHAKE_DONE) { size = ws_server_handshake(con); if (size < 0) { LM_ERR("cannot complete WebSocket handshake\n"); goto error; } d = con->proto_data; /* there is a corner case when the TLS handhskae is traced * but the connection is closed with * EOF before reaching this code if the certificate is not * validated by the client */ if ( con->flags&F_CONN_ACCEPTED && (WS_STATE(con)==WS_CON_HANDSHAKE_DONE || con->state==S_CONN_EOF) && d && d->dest && d->tprot ) { if ( d->message ) { send_trace_message( d->message, t_dst); d->message = NULL; } /* don't allow future traces for this connection */ d->tprot = 0; d->dest = 0; } if (size == 0) goto done; } if (WS_STATE(con) == WS_CON_HANDSHAKE_DONE && ws_process(con) < 0) goto error; done: return 0; error: /* connection will be released as ERROR */ return -1; }