int http_parse_input(char *src, int len, int is_cookie) { bstring name = bfromcstr(""); bstring value = bfromcstr(""); int start_pos=0, eq_pos=0, end_pos=0; int i, ret = 0; char stop = (is_cookie) ? ';' : '&'; for (i=0; i <= len; i++) { if (i == len || src[i] == stop) { end_pos = i; } else if (!eq_pos && src[i] == '=') { eq_pos = i; } if (eq_pos && end_pos && start_pos != eq_pos) { bassigncstr(name, ""); bassigncstr(value, ""); if (is_cookie) { bassigncstr(name,"COOKIE_"); bcatblk(name,src+start_pos,eq_pos-start_pos); } else { bassigncstr(name,"CAP_"); bcatblk(name,src+start_pos,eq_pos-start_pos); } /*bunescape(name);*/ if ((eq_pos + 1) == end_pos || (end_pos - eq_pos) <= 1) { syslog(LOG_DEBUG, "%s = nil", name->data); } else { bassignblk(value, src+eq_pos+1, end_pos-eq_pos-1); /*bunescape(value);*/ syslog(LOG_DEBUG, "%s = %s", name->data, value->data); setenv((char *)name->data, (char *)value->data, 1); } start_pos = end_pos + 1; if (start_pos < len) while (src[start_pos] == ' ' && i < len) i++, start_pos++; end_pos = eq_pos = 0; } } ret = 1; bdestroy(name); bdestroy(value); return ret; }
static int redir_cli_write(redir_request *req, uint8_t *d, int l) { int w = 0; if (redir_cli_rewrite(req, &req->conn) == -1) return -1; if (!conn_write_remaining(&req->conn)) { w = net_write(req->socket_fd, d, l); #if(_debug_ ) log_dbg("client write: %d", w); /*log_dbg("write: [%s]", b);*/ #endif } if (w >= 0) { if (w < l) { bcatblk(req->dbuf, d + w, l - w); log_warn(errno, "buffering %d - %d = %d (%d queued)", l, w, l-w, req->dbuf->slen); } } return w; }
static int redir_cli_write(redir_request *req, uint8_t *d, int l) { int w = 0; if (redir_cli_rewrite(req, &req->conn) == -1) return -1; if (!conn_write_remaining(&req->conn)) { w = net_write(req->socket_fd, d, l); #if(_debug_ ) syslog(LOG_DEBUG, "client write: %d", w); /*syslog(LOG_DEBUG, "write: [%s]", b);*/ #endif } if (w >= 0) { if (w < l) { bcatblk(req->dbuf, d + w, l - w); syslog(LOG_WARNING, "%s: buffering %d - %d = %d (%d queued)", strerror(errno), l, w, l-w, req->dbuf->slen); } } return w; }
static bstring genrandmsg(){ unsigned int len = WEBSOCKET_MEDIUM_MAX - 1000; printf("genrandmsg of len %u\n",len); int range = 'Z' - 'A'; bstring randchars = bfromcstr(""); for(int i=0; i<len; i++){ char randchar = 'A' + rand()%range; bcatblk(randchars,&randchar,1); } bstring retval = bformat("Len: %d Data: %.*s",len,blength(randchars),bdata(randchars)); return retval; }
static int tWrite (const void * buf, size_t elsize, size_t nelem, void * parm) { bstring b = (bstring) parm; size_t i; if (NULL == b || NULL == buf || 0 == elsize || 0 == nelem) return -__LINE__; for (i=0; i < nelem; i++) { if (0 > bcatblk (b, buf, elsize)) break; buf = (const void *) (elsize + (const char *) buf); } return (int) i; }
static int redir_handle_url(struct redir_t *redir, struct redir_conn_t *conn, struct redir_httpreq_t *httpreq, struct redir_socket_t *socket, struct sockaddr_in *peer, redir_request *req) { int port = 80; int matches = 1; int i = -1; char *p = 0; #ifdef ENABLE_REDIRINJECT char hasInject = 0; if (conn->s_params.flags & UAM_INJECT_URL) { safe_strncpy((char *) req->inject_url, (char *) conn->s_params.url, REDIRINJECT_MAX); hasInject = 1; } else if (_options.inject && *_options.inject) { safe_strncpy((char *) req->inject_url, (char *) _options.inject, REDIRINJECT_MAX); hasInject = 1; } else { #endif for (i=0; i < MAX_REGEX_PASS_THROUGHS; i++) { if ( ! _options.regex_pass_throughs[i].inuse ) break; /* if ( ! _options.regex_pass_throughs[i].regex_host[0] && ! _options.regex_pass_throughs[i].regex_path[0] && ! _options.regex_pass_throughs[i].regex_qs[0] ) break; */ #if(_debug_) log_dbg("REGEX host=[%s] path=[%s] qs=[%s]", _options.regex_pass_throughs[i].regex_host, _options.regex_pass_throughs[i].regex_path, _options.regex_pass_throughs[i].regex_qs); log_dbg("Host %s", httpreq->host); #endif if (_options.regex_pass_throughs[i].regex_host[0]) { switch(check_regex(&_options.regex_pass_throughs[i].re_host, _options.regex_pass_throughs[i].regex_host, httpreq->host)) { case -1: return -1; case 1: matches = _options.regex_pass_throughs[i].neg_host; break; case 0: matches = !_options.regex_pass_throughs[i].neg_host; break; } } if (matches && _options.regex_pass_throughs[i].regex_path[0]) { switch(check_regex(&_options.regex_pass_throughs[i].re_path, _options.regex_pass_throughs[i].regex_path, httpreq->path)) { case -1: return -1; case 1: matches = _options.regex_pass_throughs[i].neg_path; break; case 0: matches = !_options.regex_pass_throughs[i].neg_path; break; } } if (matches && _options.regex_pass_throughs[i].regex_qs[0]) { switch(check_regex(&_options.regex_pass_throughs[i].re_qs, _options.regex_pass_throughs[i].regex_qs, httpreq->qs)) { case -1: return -1; case 1: matches = _options.regex_pass_throughs[i].neg_qs; break; case 0: matches = !_options.regex_pass_throughs[i].neg_qs; break; } } if (matches) break; } #ifdef ENABLE_REDIRINJECT } #endif if (i == 0) matches = 0; if (matches) { log_dbg("Matched for Host %s", httpreq->host); req->proxy = 1; #ifdef ENABLE_REDIRINJECT /* XXX */ /* Check for headers we wish to filter out */ if (hasInject) { bstring newhdr = bfromcstr(""); char *hdr = (char *)req->wbuf->data; if (_options.inject_wispr) (void) inject_fmt(req, conn); while (hdr && *hdr) { char *p = strstr(hdr, "\r\n"); int skip = 0; int l; if (p) { l = (p - hdr); } else { l = req->wbuf->slen - (hdr - (char*)req->wbuf->data); } if (!strncasecmp(hdr, "accept-encoding:", 16)) { bcatcstr(newhdr, "Accept-Encoding: identity\r\n"); skip = 1; } else if (!strncasecmp(hdr, "connection:", 11)) { bcatcstr(newhdr, "Connection: close\r\n"); skip = 1; } else if (!strncasecmp(hdr, "keep-alive:", 11)) { skip = 1; } if (!skip) bcatblk(newhdr, hdr, l); if (p) { if (!skip) bcatblk(newhdr, p, 2); hdr = p + 2; } else { hdr = 0; } } if (req->wbuf->slen != newhdr->slen) { log_dbg("Changed HTTP Headers"); } bassign(req->wbuf, newhdr); bdestroy(newhdr); } /* XXX */ #endif if ((p = strchr(httpreq->host, ':'))) { *p++ = 0; port = atoi(p); } if (conn_setup(&req->conn, httpreq->host, port, req->wbuf, req->dbuf)) { log_err(errno, "conn_setup()"); return -1; } req->state |= REDIR_CONN_FD; net_select_addfd(&sctx, req->conn.sock, SELECT_READ); return 0; } return 1; }
static int redir_conn_read(struct conn_t *conn, void *ctx) { redir_request *req = (redir_request *)ctx; uint8_t bb[PKT_MAX_LEN]; int s, r; if ((s=redir_cli_rewrite(req, conn)) != 0) return 0; r = safe_recv(conn->sock, bb, sizeof(bb)-1, 0); #if(_debug_) log_dbg("conn_read: %d clen=%d", r, req->clen); #endif if (r == 0) { if (req->read_closed && redir_cli_rewrite(req, conn) == 0) { log_dbg("done reading and writing"); redir_conn_finish(conn, req); return -1; } req->read_closed = 1; } else if (r < 0 && errno != EWOULDBLOCK && errno != EAGAIN) { log_dbg("ERRNO %d", errno); redir_conn_finish(conn, ctx); } else if (r > 0) { #ifdef ENABLE_REDIRINJECT bstring inject = inject_fmt(req, 0); #endif bb[r]=0; req->last_active = mainclock_tick(); #ifdef ENABLE_REDIRINJECT /** * */ if (inject && !req->headers) { char *newline = "\r\n\r\n"; char *eoh; bcatblk(req->hbuf, bb, r); if ((eoh = strstr((char *)req->hbuf->data, newline))) { int header_len = eoh - (char *)req->hbuf->data; bstring newhdr = bfromcstr(""); if (strncmp((char *)req->hbuf->data, "HTTP/1.", 7) || strncmp((char *)req->hbuf->data+8, " 2", 2)) { log_dbg("Not HTTP/1.X 2XX reply"); bcatblk(newhdr, req->hbuf->data, header_len + 4); } else { char *hdr, *p; int clen = 0; hdr = (char *)req->hbuf->data; while (hdr && *hdr) { int l; p = strstr(hdr, "\r\n"); if (p == hdr) { break; } else if (p) { l = (p - hdr); } else { l = (eoh - hdr); } if (!strncasecmp(hdr, "content-length:", 15)) { char c = hdr[l]; hdr[l] = 0; clen = req->clen = atoi(hdr+15); log_dbg("Detected Content Length %d", req->clen); hdr[l] = c; } else if (!strncasecmp(hdr, "content-type:", 13)) { if (strstr(hdr, "text/html")) { req->html = 1; } } else if (strcasestr(hdr, "content-encoding: gzip")) { req->gzip = 1; } else if (strcasestr(hdr, "transfer-encoding:") && strstr(hdr,"chunked")) { req->chunked = 1; } hdr += l + 2; if (!p) break; } hdr = (char *)req->hbuf->data; while (hdr && *hdr) { int l; int skip = 0; p = strstr(hdr, "\r\n"); if (p == hdr) { break; } else if (p) { l = (p - hdr); } else { l = (eoh - hdr); } if (req->html) { if (clen && !strncasecmp(hdr, "content-length:", 15)) { char tmp[128]; if (inject) clen += inject->slen; safe_snprintf(tmp, sizeof(tmp), "Content-Length: %d\r\n", clen); bcatcstr(newhdr, tmp); skip = 1; } else if (!strncasecmp(hdr, "connection:", 11)) { skip = 1; } else if (!strncasecmp(hdr, "accept-ranges:", 14)) { skip = 1; } } log_dbg("Resp Header [%d] %.*s%s", l, l, hdr, skip ? " [Skipped]" : ""); if (!skip) { bcatblk(newhdr, hdr, l + 2); } hdr += l + 2; if (!p) break; } bcatcstr(newhdr, "Connection: close\r\n"); /* process headers */ /* Is HTML */ /* Check content-encoding chunked */ /* Adjust content-length */ bcatblk(newhdr, newline, 2); if (req->html) { if (req->chunked) { char tmp[56]; safe_snprintf(tmp, sizeof(tmp), "%x\r\n", inject->slen); bcatcstr(newhdr, tmp); } bconcat(newhdr, inject); if (req->chunked) { bcatblk(newhdr, newline, 2); } } } bcatblk(newhdr, eoh + 4, req->hbuf->slen - header_len - 4); if (req->clen > 0) /* adjust clen */ req->clen -= (req->hbuf->slen - header_len - 4); redir_cli_write(req, newhdr->data, newhdr->slen); req->headers = 1; bdestroy(newhdr); } } else { #endif redir_cli_write(req, bb, r); if (req->clen > 0) req->clen -= r; #ifdef ENABLE_REDIRINJECT } #endif } /*log_dbg("leaving redir_conn_read()");*/ return 0; }
int Connection_read_wspacket(Connection *conn) { bstring payload=NULL; uint8_t *dataU=NULL; char *data = IOBuf_start(conn->iob); int avail = IOBuf_avail(conn->iob); int64_t packet_length=-1; int smaller_packet_length; int header_length; char key[4]; int i; int data_length; int tries = 0; int rc=0; int fin; int inprogFlags=0; int isControl; int flags; again: dataU=NULL; data = IOBuf_start(conn->iob); avail = IOBuf_avail(conn->iob); packet_length=-1; smaller_packet_length=0; header_length=0; i=0; data_length=0; tries = 0; rc=0; fin=0; for(tries = 0; packet_length == -1 && tries < 8*CLIENT_READ_RETRIES; tries++) { if(avail > 0) { packet_length = Websocket_packet_length((uint8_t *)data, avail); } if(packet_length == -1) { data = IOBuf_read_some(conn->iob, &avail); check_debug(!IOBuf_closed(conn->iob), "Client closed during read."); } } check(packet_length > 0,"Error receiving websocket packet header.") check_debug(packet_length <= INT_MAX,"Websocket packet longer than MAXINT."); /* TODO properly terminate WS connection */ smaller_packet_length = (int)packet_length; /* TODO check for maximum length */ header_length=Websocket_header_length((uint8_t *) data, avail); data_length=smaller_packet_length-header_length; dataU = (uint8_t *)IOBuf_read_all(conn->iob,header_length,8*CLIENT_READ_RETRIES); memcpy(key,dataU+header_length-4,4); flags=dataU[0]; if (payload==NULL) { inprogFlags=flags; } fin=(WS_fin(dataU)); isControl=(WS_is_control(dataU)); { const char *error=WS_validate_packet(dataU,payload!=NULL); check(error==NULL,"%s",error); } dataU = (uint8_t *)IOBuf_read_all(conn->iob,data_length, 8*CLIENT_READ_RETRIES); check(dataU != NULL, "Client closed the connection during websocket packet."); for(i=0;i<data_length;++i) { dataU[i]^=key[i%4]; } if(isControl) /* Control frames get sent right-away */ { Request_set(conn->req,bfromcstr("FLAGS"),bformat("0x%X",flags|0x80),1); rc = Connection_send_to_handler(conn, conn->handler, (void *)dataU,data_length); check_debug(rc == 0, "Failed to deliver to the handler."); } else { if(fin) { Request_set(conn->req,bfromcstr("FLAGS"),bformat("0x%X",inprogFlags|0x80),1); } if (payload == NULL) { if (fin) { rc = Connection_send_to_handler(conn, conn->handler, (void *)dataU,data_length); check_debug(rc == 0, "Failed to deliver to the handler."); } else { payload = blk2bstr(dataU,data_length); check(payload != NULL,"Allocation failed"); } } else { check(BSTR_OK == bcatblk(payload,dataU,data_length), "Concatenation failed"); if (fin) { rc = Connection_send_to_handler(conn, conn->handler, bdata(payload),blength(payload)); check_debug(rc == 0, "Failed to deliver to the handler."); bdestroy(payload); payload=NULL; } } } if (payload != NULL) { goto again; } return packet_length; error: bdestroy(payload); return -1; }
static size_t save_incoming_data(char *ptr, size_t size, size_t nmemb, void *userdata) { bcatblk(userdata, ptr, size * nmemb); return size * nmemb; }