void ftp_got_user_info(struct connection *c, struct read_buffer *rb) { int g = get_ftp_response(c, rb, 0); if (g == -1) { setcstate(c, S_FTP_ERROR); abort_connection(c); return; } if (!g) { read_from_socket(c, c->sock1, rb, ftp_got_user_info); return; } if (g >= 530 && g < 540) { setcstate(c, S_FTP_LOGIN); retry_connection(c); return; } if (g >= 400) { setcstate(c, S_FTP_UNAVAIL); retry_connection(c); return; } if (g >= 200 && g < 300) { if (ftp_options.fast_ftp) ftp_dummy_info(c, rb); else ftp_send_retr_req(c, S_GETH); } else { if (ftp_options.fast_ftp) ftp_pass_info(c, rb); else { unsigned char *login; unsigned char *u; int logl = 0; login = init_str(); add_to_str(&login, &logl, "PASS "); if ((u = get_pass(c->url)) && *u) add_to_str(&login, &logl, u); else add_to_str(&login, &logl, ftp_options.anon_pass); if (u) mem_free(u); add_to_str(&login, &logl, "\r\n"); write_to_socket(c, c->sock1, login, strlen(login), ftp_sent_passwd); mem_free(login); setcstate(c, S_LOGIN); } } }
void dns_found(struct connection *c, int state) { int s; struct conn_info *b = c->newconn; if (state) { setcstate(c, S_NO_DNS); abort_connection(c); return; } if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { setcstate(c, get_error_from_errno(errno)); retry_connection(c); return; } *b->sock = s; fcntl(s, F_SETFL, O_NONBLOCK); memset(&b->sa, 0, sizeof(struct sockaddr_in)); b->sa.sin_family = AF_INET; b->sa.sin_addr.s_addr = b->addr; b->sa.sin_port = htons(b->port); if (connect(s, (struct sockaddr *)&b->sa, sizeof b->sa)) { if (errno != EALREADY && errno != EINPROGRESS) { #ifdef BEOS if (errno == EWOULDBLOCK) errno = ETIMEDOUT; #endif setcstate(c, get_error_from_errno(errno)); retry_connection(c); return; } set_handlers(s, NULL, (void(*)(void *))connected, (void(*)(void *))exception, c); setcstate(c, S_CONN); } else { connected(c); } }
static void ftp_pass_info(struct connection *c, struct read_buffer *rb) { int g = get_ftp_response(c, rb, 0); if (g == -1) { setcstate(c, S_FTP_ERROR); abort_connection(c); return; } if (!g) { read_from_socket(c, c->sock1, rb, ftp_pass_info); setcstate(c, S_LOGIN); return; } if (g >= 530 && g < 540) { setcstate(c, S_FTP_LOGIN); abort_connection(c); return; } if (g >= 400) { setcstate(c, S_FTP_UNAVAIL); abort_connection(c); return; } if (ftp_options.fast_ftp) ftp_retr_file(c, rb); else ftp_send_retr_req(c, S_GETH); }
void make_connection(struct connection *c, int port, int *sock, void (*func)(struct connection *)) { int as; unsigned char *host; struct conn_info *b; if (!(host = get_host_name(c->url))) { setcstate(c, S_INTERNAL); abort_connection(c); return; } if (c->newconn) internal("already making a connection"); b = mem_alloc(sizeof(struct conn_info)); b->func = func; b->sock = sock; b->port = port; c->newconn = b; log_data("\nCONNECTION: ", 13); log_data(host, strlen(host)); log_data("\n", 1); if (c->no_cache >= NC_RELOAD) as = find_host_no_cache(host, &b->addr, &c->dnsquery, (void(*)(void *, int))dns_found, c); else as = find_host(host, &b->addr, &c->dnsquery, (void(*)(void *, int))dns_found, c); mem_free(host); if (as) setcstate(c, S_DNS); }
void finger_get_response(struct connection *c, struct read_buffer *rb) { struct cache_entry *e; int l; set_timeout(c); if (get_cache_entry(c->url, &e)) { setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } c->cache = e; if (rb->close == 2) { setcstate(c, S_OK); finger_end_request(c); return; } l = rb->len; if (c->from + l < 0) { setcstate(c, S_LARGE_FILE); abort_connection(c); return; } c->received += l; if (add_fragment(c->cache, c->from, rb->data, l) == 1) c->tries = 0; c->from += l; kill_buffer_data(rb, l); read_from_socket(c, c->sock1, rb, finger_get_response); setcstate(c, S_TRANS); }
void ftp_got_info(struct connection *c, struct read_buffer *rb) { int g = get_ftp_response(c, rb, 0); if (g == -1) { setcstate(c, S_FTP_ERROR); abort_connection(c); return; } if (!g) { read_from_socket(c, c->sock1, rb, ftp_got_info); return; } if (g >= 400) { setcstate(c, S_FTP_UNAVAIL); retry_connection(c); return; } ftp_got_user_info(c, rb); }
void read_select(struct connection *c) { struct read_buffer *rb; int rd; if (!(rb = c->buffer)) { internal("read socket has no buffer"); setcstate(c, S_INTERNAL); abort_connection(c); return; } set_handlers(rb->sock, NULL, NULL, NULL, NULL); if ((unsigned)rb->len > MAXINT - sizeof(struct read_buffer) - READ_SIZE) overalloc(); rb = mem_realloc(rb, sizeof(struct read_buffer) + rb->len + READ_SIZE); c->buffer = rb; #ifdef HAVE_SSL if(c->ssl) { if ((rd = SSL_read(c->ssl, rb->data + rb->len, READ_SIZE)) <= 0) { int err; if ((err = SSL_get_error(c->ssl, rd)) == SSL_ERROR_WANT_READ) { read_from_socket(c, rb->sock, rb, rb->done); return; } if (rb->close && !rd) { rb->close = 2; rb->done(c, rb); return; } setcstate(c, rd ? (err == SSL_ERROR_SYSCALL ? get_error_from_errno(errno) : S_SSL_ERROR) : S_CANT_READ); /*mem_free(rb);*/ if (!rd || err == SSL_ERROR_SYSCALL) retry_connection(c); else abort_connection(c); return; } } else #endif if ((rd = read(rb->sock, rb->data + rb->len, READ_SIZE)) <= 0) { if (rb->close && !rd) { rb->close = 2; rb->done(c, rb); return; } setcstate(c, rd ? get_error_from_errno(errno) : S_CANT_READ); /*mem_free(rb);*/ retry_connection(c); return; } log_data(rb->data + rb->len, rd); rb->len += rd; rb->done(c, rb); }
void write_select(struct connection *c) { struct write_buffer *wb; int wr; if (!(wb = c->buffer)) { internal("write socket has no buffer"); setcstate(c, S_INTERNAL); abort_connection(c); return; } set_timeout(c); /*printf("ws: %d\n",wb->len-wb->pos); for (wr = wb->pos; wr < wb->len; wr++) printf("%c", wb->data[wr]); printf("-\n");*/ #ifdef HAVE_SSL if(c->ssl) { if ((wr = SSL_write(c->ssl, wb->data + wb->pos, wb->len - wb->pos)) <= 0) { int err; if ((err = SSL_get_error(c->ssl, wr)) != SSL_ERROR_WANT_WRITE) { setcstate(c, wr ? (err == SSL_ERROR_SYSCALL ? get_error_from_errno(errno) : S_SSL_ERROR) : S_CANT_WRITE); if (!wr || err == SSL_ERROR_SYSCALL) retry_connection(c); else abort_connection(c); return; } else return; } } else #endif if ((wr = write(wb->sock, wb->data + wb->pos, wb->len - wb->pos)) <= 0) { #ifdef ATHEOS /* Workaround for a bug in Syllable */ if (wr && errno == EAGAIN) { return; } #endif setcstate(c, wr ? get_error_from_errno(errno) : S_CANT_WRITE); retry_connection(c); return; } /*printf("wr: %d\n", wr);*/ if ((wb->pos += wr) == wb->len) { void (*f)(struct connection *) = wb->done; c->buffer = NULL; set_handlers(wb->sock, NULL, NULL, NULL, NULL); mem_free(wb); f(c); } }
void ssl_want_read(struct connection *c) { struct conn_info *b = c->newconn; set_timeout(c); if (c->no_tsl) c->ssl->options |= SSL_OP_NO_TLSv1; switch (SSL_get_error(c->ssl, SSL_connect(c->ssl))) { case SSL_ERROR_NONE: c->newconn = NULL; b->func(c); mem_free(b); break; case SSL_ERROR_WANT_READ: set_handlers(*b->sock, (void(*)(void *))ssl_want_read, NULL, (void(*)(void *))exception, c); break; case SSL_ERROR_WANT_WRITE: set_handlers(*b->sock, NULL, (void(*)(void *))ssl_want_read, (void(*)(void *))exception, c); break; default: c->no_tsl++; setcstate(c, S_SSL_ERROR); retry_connection(c); break; } }
void ftp_dummy_info(struct connection *c, struct read_buffer *rb) { int g = get_ftp_response(c, rb, 0); if (g == -1) { setcstate(c, S_FTP_ERROR); abort_connection(c); return; } if (!g) { read_from_socket(c, c->sock1, rb, ftp_dummy_info); return; } ftp_retr_file(c, rb); }
static void ftp_login(struct connection *c) { unsigned char *login; unsigned char *u; int logl = 0; set_timeout(c); login = init_str(); add_to_str(&login, &logl, cast_uchar "USER "); if ((u = get_user_name(c->url)) && *u) add_to_str(&login, &logl, u); else add_to_str(&login, &logl, cast_uchar "anonymous"); if (u) mem_free(u); if (ftp_options.fast_ftp) { struct ftp_connection_info *fi; add_to_str(&login, &logl, cast_uchar "\r\nPASS "); if ((u = get_pass(c->url)) && *u) add_to_str(&login, &logl, u); else add_to_str(&login, &logl, ftp_options.anon_pass); if (u) mem_free(u); add_to_str(&login, &logl, cast_uchar "\r\n"); if (!(fi = add_file_cmd_to_str(c))) { mem_free(login); return; } add_to_str(&login, &logl, fi->cmdbuf); } else add_to_str(&login, &logl, cast_uchar "\r\n"); write_to_socket(c, c->sock1, login, strlen(cast_const_char login), ftp_logged); mem_free(login); setcstate(c, S_SENT); }
int get_pasv_socket(struct connection *c, int cc, int *sock, unsigned char *port) { int s; struct sockaddr_in sa; struct sockaddr_in sb; socklen_t len = sizeof(sa); memset(&sa, 0, sizeof sa); memset(&sb, 0, sizeof sb); if (getsockname(cc, (struct sockaddr *)&sa, &len)) { e: setcstate(c, get_error_from_errno(errno)); retry_connection(c); return -1; } if ((s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) goto e; *sock = s; fcntl(s, F_SETFL, O_NONBLOCK); memcpy(&sb, &sa, sizeof(struct sockaddr_in)); sb.sin_port = 0; if (bind(s, (struct sockaddr *)&sb, sizeof sb)) goto e; len = sizeof(sa); if (getsockname(s, (struct sockaddr *)&sa, &len)) goto e; if (listen(s, 1)) goto e; memcpy(port, &sa.sin_addr.s_addr, 4); memcpy(port + 4, &sa.sin_port, 2); return 0; }
void connected(struct connection *c) { struct conn_info *b = c->newconn; int err = 0; socklen_t len = sizeof(int); if (getsockopt(*b->sock, SOL_SOCKET, SO_ERROR, (void *)&err, &len)) if (!(err = errno)) { err = -(S_STATE); goto bla; } if (err >= 10000) err -= 10000; /* Why does EMX return so large values? */ if (err > 0) { bla: setcstate(c, get_error_from_errno(err)); retry_connection(c); return; } set_timeout(c); #ifdef HAVE_SSL if (c->ssl) { c->ssl = getSSL(); SSL_set_fd(c->ssl, *b->sock); if (c->no_tsl) c->ssl->options |= SSL_OP_NO_TLSv1; switch (SSL_get_error(c->ssl, SSL_connect(c->ssl))) { case SSL_ERROR_WANT_READ: setcstate(c, S_SSL_NEG); set_handlers(*b->sock, (void(*)(void *))ssl_want_read, NULL, (void(*)(void *))exception, c); return; case SSL_ERROR_WANT_WRITE: setcstate(c, S_SSL_NEG); set_handlers(*b->sock, NULL, (void(*)(void *))ssl_want_read, (void(*)(void *))exception, c); return; case SSL_ERROR_NONE: break; default: c->no_tsl++; setcstate(c, S_SSL_ERROR); retry_connection(c); return; } } #endif c->newconn = NULL; b->func(c); mem_free(b); }
static void ftp_get_banner(struct connection *c) { struct read_buffer *rb; set_timeout(c); setcstate(c, S_SENT); if (!(rb = alloc_read_buffer(c))) return; read_from_socket(c, c->sock1, rb, ftp_got_banner); }
void finger_func(struct connection *c) { int p; if ((p = get_port(c->url)) == -1) { setcstate(c, S_INTERNAL); abort_connection(c); return; } c->from = 0; make_connection(c, p, &c->sock1, finger_send_request); }
static void finger_end_request(struct connection *c, int state) { if (state == S__OK) { if (c->cache) { truncate_entry(c->cache, c->from, 1); c->cache->incomplete = 0; } } setcstate(c, state); abort_connection(c); }
void ftp_func(struct connection *c) { /*setcstate(c, S_CONN);*/ /*set_timeout(c);*/ if (get_keepalive_socket(c)) { int p; if ((p = get_port(c->url)) == -1) { setcstate(c, S_INTERNAL); abort_connection(c); return; } make_connection(c, p, &c->sock1, ftp_options.fast_ftp ? ftp_login : ftp_get_banner); } else ftp_send_retr_req(c, S_SENT); }
void http_func(struct connection *c) { /*setcstate(c, S_CONN);*/ /*set_timeout(c);*/ if (get_keepalive_socket(c)) { int p; if ((p = get_port(c->url)) == -1) { setcstate(c, S_INTERNAL); abort_connection(c); return; } make_connection(c, p, &c->sock1, http_send_header); } else http_send_header(c); }
static void finger_get_response(struct connection *c, struct read_buffer *rb) { int l; int a; set_timeout(c); if (!c->cache) { if (get_cache_entry(c->url, &c->cache)) { setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } c->cache->refcount--; } if (rb->close == 2) { finger_end_request(c, S__OK); return; } l = rb->len; if ((off_t)(0UL + c->from + l) < 0) { setcstate(c, S_LARGE_FILE); abort_connection(c); return; } c->received += l; a = add_fragment(c->cache, c->from, rb->data, l); if (a < 0) { setcstate(c, a); abort_connection(c); return; } if (a == 1) c->tries = 0; c->from += l; kill_buffer_data(rb, l); read_from_socket(c, c->sock1, rb, finger_get_response); setcstate(c, S_TRANS); }
void finger_send_request(struct connection *c) { unsigned char *req = init_str(); int rl = 0; unsigned char *user; add_to_str(&req, &rl, "/W"); if ((user = get_user_name(c->url))) { add_to_str(&req, &rl, " "); add_to_str(&req, &rl, user); mem_free(user); } add_to_str(&req, &rl, "\r\n"); write_to_socket(c, c->sock1, req, rl, finger_sent_request); mem_free(req); setcstate(c, S_SENT); }
void ftp_send_retr_req(struct connection *c, int state) { struct ftp_connection_info *fi; unsigned char *login; int logl = 0; set_timeout(c); login = init_str(); if (!c->info && !(fi = add_file_cmd_to_str(c))) { mem_free(login); return; } else fi = c->info; if (ftp_options.fast_ftp) a:add_to_str(&login, &logl, fi->cmdbuf); else { unsigned char *nl = strchr(fi->cmdbuf, '\n'); if (!nl) goto a; nl++; add_bytes_to_str(&login, &logl, fi->cmdbuf, nl - fi->cmdbuf); memmove(fi->cmdbuf, nl, strlen(nl) + 1); } write_to_socket(c, c->sock1, login, strlen(login), ftp_retr_1); mem_free(login); setcstate(c, state); }
void http_send_header(struct connection *c) { static unsigned char *accept_charset = NULL; struct http_connection_info *info; int http10 = http_bugs.http10; struct cache_entry *e = NULL; unsigned char *hdr; unsigned char *h, *u; int l = 0; int la; unsigned char *post; unsigned char *host; find_in_cache(c->url, &c->cache); host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url); set_timeout(c); info = mem_calloc(sizeof(struct http_connection_info)); c->info = info; if ((h = get_host_name(host))) { info->bl_flags = get_blacklist_flags(h); mem_free(h); } if (info->bl_flags & BL_HTTP10) http10 = 1; info->http10 = http10; post = strchr(host, POST_CHAR); if (post) post++; hdr = init_str(); if (!post) add_to_str(&hdr, &l, "GET "); else { add_to_str(&hdr, &l, "POST "); c->unrestartable = 2; } if (upcase(c->url[0]) != 'P') add_to_str(&hdr, &l, "/"); if (!(u = get_url_data(c->url))) { mem_free(hdr); setcstate(c, S_BAD_URL); http_end_request(c, 0); return; } if (post && post < u) { mem_free(hdr); setcstate(c, S_BAD_URL); http_end_request(c, 0); return; } add_url_to_str(&hdr, &l, u); if (!http10) add_to_str(&hdr, &l, " HTTP/1.1\r\n"); else add_to_str(&hdr, &l, " HTTP/1.0\r\n"); if ((h = get_host_name(host))) { add_to_str(&hdr, &l, "Host: "); add_to_str(&hdr, &l, h); mem_free(h); if ((h = get_port_str(host))) { add_to_str(&hdr, &l, ":"); add_to_str(&hdr, &l, h); mem_free(h); } add_to_str(&hdr, &l, "\r\n"); } add_to_str(&hdr, &l, "User-Agent: "); if (!(*http_bugs.fake_useragent)) { add_to_str(&hdr, &l, "Links (" VERSION_STRING "; "); add_to_str(&hdr, &l, system_name); if (!F && !list_empty(terminals)) { struct terminal *t = terminals.prev; if (!t->spec->braille) { add_to_str(&hdr, &l, "; "); add_num_to_str(&hdr, &l, t->x); add_to_str(&hdr, &l, "x"); add_num_to_str(&hdr, &l, t->y); } else { add_to_str(&hdr, &l, "; braille"); } } #ifdef G if (F && drv) { add_to_str(&hdr, &l, "; "); add_to_str(&hdr, &l, drv->name); } #endif add_to_str(&hdr, &l, ")\r\n"); } else { add_to_str(&hdr, &l, http_bugs.fake_useragent); add_to_str(&hdr, &l, "\r\n"); } switch (http_bugs.referer) { case REFERER_FAKE: add_to_str(&hdr, &l, "Referer: "); add_to_str(&hdr, &l, http_bugs.fake_referer); add_to_str(&hdr, &l, "\r\n"); break; case REFERER_SAME_URL: add_to_str(&hdr, &l, "Referer: "); add_url_to_str(&hdr, &l, host); add_to_str(&hdr, &l, "\r\n"); break; case REFERER_REAL_SAME_SERVER: { unsigned char *h, *j; int brk = 1; if ((h = get_host_name(host))) { if ((j = get_host_name(c->prev_url))) { if (!strcasecmp(h, j)) brk = 0; mem_free(j); } mem_free(h); } if (brk) break; /* fall through */ } case REFERER_REAL: { unsigned char *ref; unsigned char *user, *ins; int ulen; if (!(c->prev_url)) break; /* no referrer */ ref = stracpy(c->prev_url); if (!parse_url(ref, NULL, &user, &ulen, NULL, NULL, &ins, NULL, NULL, NULL, NULL, NULL, NULL) && ulen && ins) { memmove(user, ins, strlen(ins) + 1); } add_to_str(&hdr, &l, "Referer: "); add_url_to_str(&hdr, &l, ref); add_to_str(&hdr, &l, "\r\n"); mem_free(ref); } break; } add_to_str(&hdr, &l, "Accept: */*\r\n"); #if defined(HAVE_ZLIB) || defined(HAVE_BZIP2) if (!http_bugs.no_compression && !(info->bl_flags & BL_NO_COMPRESSION)) { int q = strlen(c->url); if (q >= 2 && !strcasecmp(c->url + q - 2, ".Z")) goto skip_compress; if (q >= 3 && !strcasecmp(c->url + q - 3, ".gz")) goto skip_compress; if (q >= 4 && !strcasecmp(c->url + q - 4, ".bz2")) goto skip_compress; add_to_str(&hdr, &l, "Accept-Encoding: "); #if defined(HAVE_ZLIB) add_to_str(&hdr, &l, "gzip, deflate, "); #endif #if defined(HAVE_BZIP2) add_to_str(&hdr, &l, "bzip2, "); #endif hdr[l-2] = '\r'; hdr[l-1] = '\n'; skip_compress: ; } #endif if (!(accept_charset)) { int i; unsigned char *cs, *ac; int aclen = 0; ac = init_str(); for (i = 0; (cs = get_cp_mime_name(i)); i++) { if (aclen) add_to_str(&ac, &aclen, ", "); else add_to_str(&ac, &aclen, "Accept-Charset: "); add_to_str(&ac, &aclen, cs); } if (aclen) add_to_str(&ac, &aclen, "\r\n"); if ((accept_charset = malloc(strlen(ac) + 1))) strcpy(accept_charset, ac); else accept_charset = ""; mem_free(ac); } if (!(info->bl_flags & BL_NO_CHARSET) && !http_bugs.no_accept_charset) add_to_str(&hdr, &l, accept_charset); if (!(info->bl_flags & BL_NO_ACCEPT_LANGUAGE)) { add_to_str(&hdr, &l, "Accept-Language: "); la = l; add_to_str(&hdr, &l, _(TEXT(T__ACCEPT_LANGUAGE), NULL)); add_to_str(&hdr, &l, ", "); if (!strstr(hdr + la, "en,") && !strstr(hdr + la, "en;")) add_to_str(&hdr, &l, "en;q=0.2, "); add_to_str(&hdr, &l, "*;q=0.1\r\n"); } if (!http10) { if (upcase(c->url[0]) != 'P') add_to_str(&hdr, &l, "Connection: "); else add_to_str(&hdr, &l, "Proxy-Connection: "); if (!post || !http_bugs.bug_post_no_keepalive) add_to_str(&hdr, &l, "Keep-Alive\r\n"); else add_to_str(&hdr, &l, "close\r\n"); } if ((e = c->cache)) { int code, vers; if (get_http_code(e->head, &code, &vers) || code >= 400) goto skip_ifmod_and_range; if (!e->incomplete && e->head && c->no_cache <= NC_IF_MOD) { unsigned char *m; if (e->last_modified) m = stracpy(e->last_modified); else if ((m = parse_http_header(e->head, "Date", NULL))) ; else if ((m = parse_http_header(e->head, "Expires", NULL))) ; else goto skip_ifmod; add_to_str(&hdr, &l, "If-Modified-Since: "); add_to_str(&hdr, &l, m); add_to_str(&hdr, &l, "\r\n"); mem_free(m); } skip_ifmod: ; } if (c->from && (c->est_length == -1 || c->from < c->est_length) && c->no_cache < NC_IF_MOD && !(info->bl_flags & BL_NO_RANGE)) { /* If the cached entity is compressed and we turned off compression, request the whole file */ if ((info->bl_flags & BL_NO_COMPRESSION || http_bugs.no_compression) && e) { unsigned char *d; if ((d = parse_http_header(e->head, "Transfer-Encoding", NULL))) { mem_free(d); goto skip_range; } } add_to_str(&hdr, &l, "Range: bytes="); add_num_to_str(&hdr, &l, c->from); add_to_str(&hdr, &l, "-\r\n"); skip_range: ; } skip_ifmod_and_range: if (c->no_cache >= NC_PR_NO_CACHE) add_to_str(&hdr, &l, "Pragma: no-cache\r\nCache-Control: no-cache\r\n"); if ((h = get_auth_string(c->url))) { add_to_str(&hdr, &l, h); mem_free(h); } if (post) { unsigned char *pd = strchr(post, '\n'); if (pd) { add_to_str(&hdr, &l, "Content-Type: "); add_bytes_to_str(&hdr, &l, post, pd - post); add_to_str(&hdr, &l, "\r\n"); post = pd + 1; } add_to_str(&hdr, &l, "Content-Length: "); add_num_to_str(&hdr, &l, strlen(post) / 2); add_to_str(&hdr, &l, "\r\n"); } send_cookies(&hdr, &l, host); add_to_str(&hdr, &l, "\r\n"); if (post) { while (post[0] && post[1]) { int h1, h2; h1 = post[0] <= '9' ? (unsigned)post[0] - '0' : post[0] >= 'A' ? upcase(post[0]) - 'A' + 10 : 0; if (h1 < 0 || h1 >= 16) h1 = 0; h2 = post[1] <= '9' ? (unsigned)post[1] - '0' : post[1] >= 'A' ? upcase(post[1]) - 'A' + 10 : 0; if (h2 < 0 || h2 >= 16) h2 = 0; add_chr_to_str(&hdr, &l, h1 * 16 + h2); post += 2; } } write_to_socket(c, c->sock1, hdr, l, http_get_header); mem_free(hdr); setcstate(c, S_SENT); }
static struct ftp_connection_info *add_file_cmd_to_str(struct connection *c) { unsigned char *d = get_url_data(c->url); unsigned char *de; int del; unsigned char port_string[50]; struct ftp_connection_info *inf, *inf2; unsigned char *s; int l; if (!d) { internal("get_url_data failed"); setcstate(c, S_INTERNAL); abort_connection(c); return NULL; } de = init_str(), del = 0; add_conv_str(&de, &del, d, strlen(cast_const_char d), -2); d = de; inf = mem_alloc(sizeof(struct ftp_connection_info)); memset(inf, 0, sizeof(struct ftp_connection_info)); l = 0; s = init_str(); inf->pasv = ftp_options.passive_ftp; #ifdef LINKS_2 if (*c->socks_proxy) inf->pasv = 1; if (ftp_options.eprt_epsv || is_ipv6(c->sock1)) inf->eprt_epsv = 1; #endif c->info = inf; if (!inf->pasv) { int ps; #ifdef SUPPORT_IPV6 if (is_ipv6(c->sock1)) { ps = get_pasv_socket_ipv6(c, c->sock1, &c->sock2, port_string); if (ps) { mem_free(d); mem_free(s); return NULL; } } else #endif { unsigned char pc[6]; ps = get_pasv_socket(c, c->sock1, &c->sock2, pc); if (ps) { mem_free(d); mem_free(s); return NULL; } if (inf->eprt_epsv) sprintf(cast_char port_string, "|1|%d.%d.%d.%d|%d|", pc[0], pc[1], pc[2], pc[3], (pc[4] << 8) | pc[5]); else sprintf(cast_char port_string, "%d,%d,%d,%d,%d,%d", pc[0], pc[1], pc[2], pc[3], pc[4], pc[5]); } if (strlen(cast_const_char port_string) >= sizeof(port_string)) internal("buffer overflow in get_pasv_socket_ipv6: %d > %d", (int)strlen(cast_const_char port_string), (int)sizeof(port_string)); } #ifdef HAVE_IPTOS if (ftp_options.set_tos) { int rx; int on = IPTOS_THROUGHPUT; EINTRLOOP(rx, setsockopt(c->sock2, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int))); } #endif if (!(de = cast_uchar strchr(cast_const_char d, POST_CHAR))) de = d + strlen(cast_const_char d); if (d == de || de[-1] == '/') { inf->dir = 1; inf->pending_commands = 4; add_to_str(&s, &l, cast_uchar "TYPE A\r\n"); add_port_pasv(&s, &l, inf, port_string); add_to_str(&s, &l, cast_uchar "CWD /"); add_bytes_to_str(&s, &l, d, de - d); add_to_str(&s, &l, cast_uchar "\r\nLIST\r\n"); c->from = 0; } else { inf->dir = 0; inf->pending_commands = 3; add_to_str(&s, &l, cast_uchar "TYPE I\r\n"); add_port_pasv(&s, &l, inf, port_string); if (c->from && c->no_cache < NC_IF_MOD) { add_to_str(&s, &l, cast_uchar "REST "); add_num_to_str(&s, &l, c->from); add_to_str(&s, &l, cast_uchar "\r\n"); inf->rest_sent = 1; inf->pending_commands++; } else c->from = 0; add_to_str(&s, &l, cast_uchar "RETR /"); add_bytes_to_str(&s, &l, d, de - d); add_to_str(&s, &l, cast_uchar "\r\n"); } inf->opc = inf->pending_commands; if ((unsigned)l > MAXINT - sizeof(struct ftp_connection_info) - 1) overalloc(); inf2 = mem_realloc(inf, sizeof(struct ftp_connection_info) + l + 1); strcpy(cast_char (inf = inf2)->cmdbuf, cast_const_char s); mem_free(s); c->info = inf; mem_free(d); return inf; }
void exception(struct connection *c) { setcstate(c, S_EXCEPT); retry_connection(c); }
struct ftp_connection_info *add_file_cmd_to_str(struct connection *c) { unsigned char *d = get_url_data(c->url); unsigned char *de; int del; unsigned char pc[6]; int ps; struct ftp_connection_info *inf, *inf2; unsigned char *s; int l; if (!d) { internal("get_url_data failed"); setcstate(c, S_INTERNAL); abort_connection(c); return NULL; } de = init_str(), del = 0; add_conv_str(&de, &del, d, strlen(d), -2); d = de; inf = mem_alloc(sizeof(struct ftp_connection_info)); memset(inf, 0, sizeof(struct ftp_connection_info)); l = 0; s = init_str(); inf->pasv = ftp_options.passive_ftp; if (*c->socks_proxy) inf->pasv = 1; c->info = inf; if (!inf->pasv) if ((ps = get_pasv_socket(c, c->sock1, &c->sock2, pc))) { mem_free(d); return NULL; } #ifdef HAVE_IPTOS if (ftp_options.set_tos) { int on = IPTOS_THROUGHPUT; setsockopt(c->sock2, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)); } #endif if (!(de = strchr(d, POST_CHAR))) de = d + strlen(d); if (d == de || de[-1] == '/') { inf->dir = 1; inf->pending_commands = 4; add_to_str(&s, &l, "TYPE A\r\n"); if (!inf->pasv) { add_to_str(&s, &l, "PORT "); add_num_to_str(&s, &l, pc[0]); add_chr_to_str(&s, &l, ','); add_num_to_str(&s, &l, pc[1]); add_chr_to_str(&s, &l, ','); add_num_to_str(&s, &l, pc[2]); add_chr_to_str(&s, &l, ','); add_num_to_str(&s, &l, pc[3]); add_chr_to_str(&s, &l, ','); add_num_to_str(&s, &l, pc[4]); add_chr_to_str(&s, &l, ','); add_num_to_str(&s, &l, pc[5]); add_to_str(&s, &l, "\r\n"); } else { add_to_str(&s, &l, "PASV\r\n"); } add_to_str(&s, &l, "CWD /"); add_bytes_to_str(&s, &l, d, de - d); add_to_str(&s, &l, "\r\nLIST\r\n"); c->from = 0; } else { inf->dir = 0; inf->pending_commands = 3; add_to_str(&s, &l, "TYPE I\r\n"); if (!inf->pasv) { add_to_str(&s, &l, "PORT "); add_num_to_str(&s, &l, pc[0]); add_chr_to_str(&s, &l, ','); add_num_to_str(&s, &l, pc[1]); add_chr_to_str(&s, &l, ','); add_num_to_str(&s, &l, pc[2]); add_chr_to_str(&s, &l, ','); add_num_to_str(&s, &l, pc[3]); add_chr_to_str(&s, &l, ','); add_num_to_str(&s, &l, pc[4]); add_chr_to_str(&s, &l, ','); add_num_to_str(&s, &l, pc[5]); add_to_str(&s, &l, "\r\n"); } else { add_to_str(&s, &l, "PASV\r\n"); } if (c->from && c->no_cache < NC_IF_MOD) { add_to_str(&s, &l, "REST "); add_num_to_str(&s, &l, c->from); add_to_str(&s, &l, "\r\n"); inf->rest_sent = 1; inf->pending_commands++; } else c->from = 0; add_to_str(&s, &l, "RETR /"); add_bytes_to_str(&s, &l, d, de - d); add_to_str(&s, &l, "\r\n"); } inf->opc = inf->pending_commands; if ((unsigned)l > MAXINT - sizeof(struct ftp_connection_info) - 1) overalloc(); inf2 = mem_realloc(inf, sizeof(struct ftp_connection_info) + l + 1); strcpy((inf = inf2)->cmdbuf, s); mem_free(s); c->info = inf; mem_free(d); return inf; }
void http_got_header(struct connection *c, struct read_buffer *rb) { int cf; int state = c->state != S_PROC ? S_GETH : S_PROC; unsigned char *head; unsigned char *cookie, *ch; int a, h, version; unsigned char *d; struct cache_entry *e; struct http_connection_info *info; unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url); set_timeout(c); info = c->info; if (rb->close == 2) { unsigned char *h; if (!c->tries && (h = get_host_name(host))) { if (info->bl_flags & BL_NO_CHARSET) { del_blacklist_entry(h, BL_NO_CHARSET); } else { add_blacklist_entry(h, BL_NO_CHARSET); c->tries = -1; } mem_free(h); } setcstate(c, S_CANT_READ); retry_connection(c); return; } rb->close = 0; again: if ((a = get_header(rb)) == -1) { setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if (!a) { read_from_socket(c, c->sock1, rb, http_got_header); setcstate(c, state); return; } if (a != -2) { head = mem_alloc(a + 1); memcpy(head, rb->data, a); head[a] = 0; kill_buffer_data(rb, a); } else { head = stracpy("HTTP/0.9 200 OK\r\nContent-Type: text/html\r\n\r\n"); } if (get_http_code(head, &h, &version) || h == 101) { mem_free(head); setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if (check_http_server_bugs(host, c->info, head) && is_connection_restartable(c)) { mem_free(head); setcstate(c, S_RESTART); retry_connection(c); return; } ch = head; while ((cookie = parse_http_header(ch, "Set-Cookie", &ch))) { unsigned char *host = upcase(c->url[0]) != 'P' ? c->url : get_url_data(c->url); set_cookie(NULL, host, cookie); mem_free(cookie); } if (h == 100) { mem_free(head); state = S_PROC; goto again; } if (h < 200) { mem_free(head); setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if (h == 204) { mem_free(head); setcstate(c, S_HTTP_204); http_end_request(c, 0); return; } if (h == 304) { mem_free(head); setcstate(c, S_OK); http_end_request(c, 1); return; } if ((h == 500 || h == 502 || h == 503 || h == 504) && http_bugs.retry_internal_errors && is_connection_restartable(c)) { /* !!! FIXME: wait some time ... */ mem_free(head); setcstate(c, S_RESTART); retry_connection(c); return; } if (!c->cache && get_cache_entry(c->url, &c->cache)) { mem_free(head); setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } e = c->cache; e->http_code = h; if (e->head) mem_free(e->head); e->head = head; if ((d = parse_http_header(head, "Expires", NULL))) { time_t t = parse_http_date(d); if (t && e->expire_time != 1) e->expire_time = t; mem_free(d); } if ((d = parse_http_header(head, "Pragma", NULL))) { if (!casecmp(d, "no-cache", 8)) e->expire_time = 1; mem_free(d); } if ((d = parse_http_header(head, "Cache-Control", NULL))) { char *f = d; while (1) { while (*f && (*f == ' ' || *f == ',')) f++; if (!*f) break; if (!casecmp(f, "no-cache", 8) || !casecmp(f, "must-revalidate", 15)) { e->expire_time = 1; } if (!casecmp(f, "max-age=", 8)) { if (e->expire_time != 1) e->expire_time = time(NULL) + atoi(f + 8); } while (*f && *f != ',') f++; } mem_free(d); } #ifdef HAVE_SSL if (c->ssl) { int l = 0; if (e->ssl_info) mem_free(e->ssl_info); e->ssl_info = init_str(); add_num_to_str(&e->ssl_info, &l, SSL_get_cipher_bits(c->ssl, NULL)); add_to_str(&e->ssl_info, &l, "-bit "); add_to_str(&e->ssl_info, &l, SSL_get_cipher_version(c->ssl)); add_to_str(&e->ssl_info, &l, " "); add_to_str(&e->ssl_info, &l, (unsigned char *)SSL_get_cipher_name(c->ssl)); } #endif if (e->redirect) mem_free(e->redirect), e->redirect = NULL; if (h == 301 || h == 302 || h == 303 || h == 307) { if ((h == 302 || h == 307) && !e->expire_time) e->expire_time = 1; if ((d = parse_http_header(e->head, "Location", NULL))) { unsigned char *user, *ins; unsigned char *newuser, *newpassword; if (!parse_url(d, NULL, &user, NULL, NULL, NULL, &ins, NULL, NULL, NULL, NULL, NULL, NULL) && !user && ins && (newuser = get_user_name(host))) { if (*newuser) { int ins_off = ins - d; newpassword = get_pass(host); if (!newpassword) newpassword = stracpy(""); add_to_strn(&newuser, ":"); add_to_strn(&newuser, newpassword); add_to_strn(&newuser, "@"); extend_str(&d, strlen(newuser)); ins = d + ins_off; memmove(ins + strlen(newuser), ins, strlen(ins) + 1); memcpy(ins, newuser, strlen(newuser)); mem_free(newpassword); } mem_free(newuser); } if (e->redirect) mem_free(e->redirect); e->redirect = d; e->redirect_get = h == 303; } } if (!e->expire_time && strchr(c->url, POST_CHAR)) e->expire_time = 1; info->close = 0; info->length = -1; info->version = version; if ((d = parse_http_header(e->head, "Connection", NULL)) || (d = parse_http_header(e->head, "Proxy-Connection", NULL))) { if (!strcasecmp(d, "close")) info->close = 1; mem_free(d); } else if (version < 11) info->close = 1; cf = c->from; c->from = 0; if ((d = parse_http_header(e->head, "Content-Range", NULL))) { if (strlen(d) > 6) { d[5] = 0; if (!(strcasecmp(d, "bytes")) && d[6] >= '0' && d[6] <= '9') { #if defined(HAVE_STRTOLL) long long f = strtoll(d + 6, NULL, 10); #elif defined(HAVE_STRTOQ) longlong f = strtoq(d + 6, NULL, 10); #else long f = strtol(d + 6, NULL, 10); if (f == MAXLONG) f = -1; #endif if (f >= 0 && (off_t)f >= 0 && (off_t)f == f) c->from = f; } } mem_free(d); } if (cf && !c->from && !c->unrestartable) c->unrestartable = 1; if (c->from > cf || c->from < 0) { setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if ((d = parse_http_header(e->head, "Content-Length", NULL))) { unsigned char *ep; #if defined(HAVE_STRTOLL) long long l = strtoll(d, (char **)(void *)&ep, 10); #elif defined(HAVE_STRTOQ) longlong l = strtoq(d, (char **)(void *)&ep, 10); #else long l = strtol(d, (char **)(void *)&ep, 10); if (l == MAXLONG) l = -1; #endif if (!*ep && l >= 0 && (off_t)l >= 0 && (off_t)l == l) { if (!info->close || version >= 11) info->length = l; if (c->from + l >= 0) c->est_length = c->from + l; } mem_free(d); } if ((d = parse_http_header(e->head, "Accept-Ranges", NULL))) { if (!strcasecmp(d, "none") && !c->unrestartable) c->unrestartable = 1; mem_free(d); } else { if (!c->unrestartable && !c->from) c->unrestartable = 1; } if (info->bl_flags & BL_NO_RANGE && !c->unrestartable) c->unrestartable = 1; if ((d = parse_http_header(e->head, "Transfer-Encoding", NULL))) { if (!strcasecmp(d, "chunked")) { info->length = -2; info->chunk_remaining = -1; } mem_free(d); } if (!info->close && info->length == -1) info->close = 1; if ((d = parse_http_header(e->head, "Last-Modified", NULL))) { if (e->last_modified && strcasecmp(e->last_modified, d)) { delete_entry_content(e); if (c->from) { c->from = 0; mem_free(d); setcstate(c, S_MODIFIED); retry_connection(c); return; } } if (!e->last_modified) e->last_modified = d; else mem_free(d); } if (!e->last_modified && (d = parse_http_header(e->head, "Date", NULL))) e->last_modified = d; if (info->length == -1 || (version < 11 && info->close)) rb->close = 1; read_http_data(c, rb); }
void https_func(struct connection *c) { setcstate(c, S_NO_SSL); abort_connection(c); }
void file_func(struct connection *c) { struct cache_entry *e; unsigned char *file, *name, *head; int fl; DIR *d; int h, r; struct stat stt; if (anonymous && !anonymousGinga) { setcstate(c, S_BAD_URL); abort_connection(c); return; } if (!(name = get_filename(c->url))) { setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } if (anonymousGinga && !allowedPath(name)){ setcstate(c, S_BAD_URL); abort_connection(c); return; } if (stat(name, &stt)) { mem_free(name); setcstate(c, -errno); abort_connection(c); return; } if (!S_ISDIR(stt.st_mode) && !S_ISREG(stt.st_mode)) { mem_free(name); setcstate(c, S_FILE_TYPE); abort_connection(c); return; } if ((h = open(name, O_RDONLY | O_NOCTTY)) == -1) { int er = errno; if ((d = opendir(name))) goto dir; mem_free(name); setcstate(c, -er); abort_connection(c); return; } set_bin(h); if (S_ISDIR(stt.st_mode)) { struct dirs *dir; int dirl; int i; struct dirent *de; d = opendir(name); close(h); if (!d) { mem_free(name); setcstate(c, -errno); abort_connection(c); return; } dir: dir = DUMMY, dirl = 0; if (name[0] && !dir_sep(name[strlen(name) - 1])) { if (get_cache_entry(c->url, &e)) { mem_free(name); closedir(d); setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } c->cache = e; if (e->redirect) mem_free(e->redirect); e->redirect = stracpy(c->url); e->redirect_get = 1; add_to_strn(&e->redirect, "/"); mem_free(name); closedir(d); goto end; } last_uid = -1; last_gid = -1; file = init_str(); fl = 0; add_to_str(&file, &fl, "<html><head><title>"); add_conv_str(&file, &fl, name, strlen(name), -1); add_to_str(&file, &fl, "</title></head><body><h2>Directory "); add_conv_str(&file, &fl, name, strlen(name), -1); add_to_str(&file, &fl, "</h2><pre>"); while ((de = readdir(d))) { struct stat stt, *stp; unsigned char **p; int l; unsigned char *n; if (!strcmp(de->d_name, ".")) continue; if ((unsigned)dirl > MAXINT / sizeof(struct dirs) - 1) overalloc(); dir = mem_realloc(dir, (dirl + 1) * sizeof(struct dirs)); dir[dirl].f = stracpy(de->d_name); *(p = &dir[dirl++].s) = init_str(); l = 0; n = stracpy(name); add_to_strn(&n, de->d_name); #ifdef FS_UNIX_SOFTLINKS if (lstat(n, &stt)) #else if (stat(n, &stt)) #endif stp = NULL; else stp = &stt; mem_free(n); stat_mode(p, &l, stp); stat_links(p, &l, stp); stat_user(p, &l, stp, 0); stat_user(p, &l, stp, 1); stat_size(p, &l, stp); stat_date(p, &l, stp); } closedir(d); if (dirl) qsort(dir, dirl, sizeof(struct dirs), (int(*)(const void *, const void *))comp_de); for (i = 0; i < dirl; i++) { unsigned char *lnk = NULL; #ifdef FS_UNIX_SOFTLINKS if (dir[i].s[0] == 'l') { unsigned char *buf = NULL; int size = 0; int r; unsigned char *n = stracpy(name); add_to_strn(&n, dir[i].f); do { if (buf) mem_free(buf); size += ALLOC_GR; if ((unsigned)size > MAXINT) overalloc(); buf = mem_alloc(size); r = readlink(n, buf, size); } while (r == size); if (r == -1) goto yyy; buf[r] = 0; lnk = buf; goto xxx; yyy: mem_free(buf); xxx: mem_free(n); } #endif /*add_to_str(&file, &fl, " ");*/ add_to_str(&file, &fl, dir[i].s); add_to_str(&file, &fl, "<a href=\""); add_conv_str(&file, &fl, dir[i].f, strlen(dir[i].f), 1); if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "/"); else if (lnk) { struct stat st; unsigned char *n = stracpy(name); add_to_strn(&n, dir[i].f); if (!stat(n, &st)) if (S_ISDIR(st.st_mode)) add_to_str(&file, &fl, "/"); mem_free(n); } add_to_str(&file, &fl, "\">"); /*if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "<font color=\"yellow\">");*/ add_conv_str(&file, &fl, dir[i].f, strlen(dir[i].f), 0); /*if (dir[i].s[0] == 'd') add_to_str(&file, &fl, "</font>");*/ add_to_str(&file, &fl, "</a>"); if (lnk) { add_to_str(&file, &fl, " -> "); add_to_str(&file, &fl, lnk); mem_free(lnk); } add_to_str(&file, &fl, "\n"); } mem_free(name); for (i = 0; i < dirl; i++) mem_free(dir[i].s), mem_free(dir[i].f); mem_free(dir); add_to_str(&file, &fl, "</pre></body></html>\n"); head = stracpy("\r\nContent-Type: text/html\r\n"); } else { mem_free(name); /* + !stt.st_size is there because of bug in Linux. Read returns -EACCES when reading 0 bytes to invalid address */ if (stt.st_size > MAXINT) { close(h); setcstate(c, S_LARGE_FILE); abort_connection(c); return; } file = mem_alloc(stt.st_size + !stt.st_size); if ((r = read(h, file, stt.st_size)) != stt.st_size) { mem_free(file); close(h); setcstate(c, r == -1 ? -errno : S_FILE_ERROR); abort_connection(c); return; } close(h); fl = stt.st_size; head = stracpy(""); } if (get_cache_entry(c->url, &e)) { mem_free(file); setcstate(c, S_OUT_OF_MEM); abort_connection(c); return; } if (e->head) mem_free(e->head); e->head = head; c->cache = e; add_fragment(e, 0, file, fl); truncate_entry(e, fl, 1); mem_free(file); end: c->cache->incomplete = 0; setcstate(c, S_OK); abort_connection(c); }
void read_http_data(struct connection *c, struct read_buffer *rb) { struct http_connection_info *info = c->info; set_timeout(c); if (rb->close == 2) { setcstate(c, S_OK); http_end_request(c, 0); return; } if (info->length != -2) { int l = rb->len; if (info->length >= 0 && info->length < l) l = info->length; if (c->from + l < 0) { setcstate(c, S_LARGE_FILE); abort_connection(c); return; } c->received += l; if (add_fragment(c->cache, c->from, rb->data, l) == 1) c->tries = 0; if (info->length >= 0) info->length -= l; c->from += l; kill_buffer_data(rb, l); if (!info->length && !rb->close) { setcstate(c, S_OK); http_end_request(c, 0); return; } } else { next_chunk: if (info->chunk_remaining == -2) { int l; if ((l = is_line_in_buffer(rb))) { if (l == -1) { setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } kill_buffer_data(rb, l); if (l <= 2) { setcstate(c, S_OK); http_end_request(c, 0); return; } goto next_chunk; } } else if (info->chunk_remaining == -1) { int l; if ((l = is_line_in_buffer(rb))) { unsigned char *de; long n = 0; /* warning, go away */ if (l != -1) n = strtol(rb->data, (char **)(void *)&de, 16); if (l == -1 || n < 0 || n >= MAXINT || de == rb->data) { setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } kill_buffer_data(rb, l); if (!(info->chunk_remaining = n)) info->chunk_remaining = -2; goto next_chunk; } } else { int l = info->chunk_remaining; if (l > rb->len) l = rb->len; if (c->from + l < 0) { setcstate(c, S_LARGE_FILE); abort_connection(c); return; } c->received += l; if (add_fragment(c->cache, c->from, rb->data, l) == 1) c->tries = 0; info->chunk_remaining -= l; c->from += l; kill_buffer_data(rb, l); if (!info->chunk_remaining && rb->len >= 1) { if (rb->data[0] == 10) kill_buffer_data(rb, 1); else { if (rb->data[0] != 13 || (rb->len >= 2 && rb->data[1] != 10)) { setcstate(c, S_HTTP_ERROR); abort_connection(c); return; } if (rb->len < 2) goto read_more; kill_buffer_data(rb, 2); } info->chunk_remaining = -1; goto next_chunk; } } } read_more: read_from_socket(c, c->sock1, rb, read_http_data); setcstate(c, S_TRANS); }