static void ftp_got_banner(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_banner); return; } if (g >= 400) { setcstate(c, S_FTP_UNAVAIL); retry_connection(c); return; } ftp_login(c); }
static void tcp_retry_expired(struct k_timer *timer) { struct net_tcp *tcp = CONTAINER_OF(timer, struct net_tcp, retry_timer); struct net_pkt *pkt; /* Double the retry period for exponential backoff and resent * the first (only the first!) unack'd packet. */ if (!sys_slist_is_empty(&tcp->sent_list)) { tcp->retry_timeout_shift++; if (tcp->retry_timeout_shift > CONFIG_NET_TCP_RETRY_COUNT) { abort_connection(tcp); return; } k_timer_start(&tcp->retry_timer, retry_timeout(tcp), 0); pkt = CONTAINER_OF(sys_slist_peek_head(&tcp->sent_list), struct net_pkt, sent_list); if (net_pkt_sent(pkt)) { do_ref_if_needed(tcp, pkt); net_pkt_set_sent(pkt, false); } net_pkt_set_queued(pkt, true); if (net_tcp_send_pkt(pkt) < 0 && !is_6lo_technology(pkt)) { NET_DBG("[%p] pkt %p send failed", tcp, pkt); net_pkt_unref(pkt); } else { NET_DBG("[%p] sent pkt %p", tcp, pkt); if (IS_ENABLED(CONFIG_NET_STATISTICS_TCP) && !is_6lo_technology(pkt)) { net_stats_update_tcp_seg_rexmit(); } } } else if (IS_ENABLED(CONFIG_NET_TCP_TIME_WAIT)) {
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); }
/*---------------------------------------------------------------------------*/ PROCESS_THREAD(mqtt_process, ev, data) { static struct mqtt_connection *conn; PROCESS_BEGIN(); while(1) { PROCESS_WAIT_EVENT(); if(ev == mqtt_abort_now_event) { DBG("MQTT - Abort\n"); conn = data; conn->state = MQTT_CONN_STATE_ABORT_IMMEDIATE; abort_connection(conn); } if(ev == mqtt_do_connect_tcp_event) { conn = data; DBG("MQTT - Got mqtt_do_connect_tcp_event!\n"); connect_tcp(conn); } if(ev == mqtt_do_connect_mqtt_event) { conn = data; conn->socket.output_data_max_seg = conn->max_segment_size; DBG("MQTT - Got mqtt_do_connect_mqtt_event!\n"); if(conn->out_buffer_sent == 1) { PT_INIT(&conn->out_proto_thread); while(connect_pt(&conn->out_proto_thread, conn) < PT_EXITED && conn->state != MQTT_CONN_STATE_ABORT_IMMEDIATE) { PT_MQTT_WAIT_SEND(); } } } if(ev == mqtt_do_disconnect_mqtt_event) { conn = data; DBG("MQTT - Got mqtt_do_disconnect_mqtt_event!\n"); /* Send MQTT Disconnect if we are connected */ if(conn->state == MQTT_CONN_STATE_SENDING_MQTT_DISCONNECT) { if(conn->out_buffer_sent == 1) { PT_INIT(&conn->out_proto_thread); while(disconnect_pt(&conn->out_proto_thread, conn) < PT_EXITED && conn->state != MQTT_CONN_STATE_ABORT_IMMEDIATE) { PT_MQTT_WAIT_SEND(); } abort_connection(conn); call_event(conn, MQTT_EVENT_DISCONNECTED, &ev); } else { process_post(&mqtt_process, mqtt_do_disconnect_mqtt_event, conn); } } } if(ev == mqtt_do_pingreq_event) { conn = data; DBG("MQTT - Got mqtt_do_pingreq_event!\n"); if(conn->out_buffer_sent == 1 && conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) { PT_INIT(&conn->out_proto_thread); while(pingreq_pt(&conn->out_proto_thread, conn) < PT_EXITED && conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) { PT_MQTT_WAIT_SEND(); } } } if(ev == mqtt_do_subscribe_event) { conn = data; DBG("MQTT - Got mqtt_do_subscribe_mqtt_event!\n"); if(conn->out_buffer_sent == 1 && conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) { PT_INIT(&conn->out_proto_thread); while(subscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED && conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) { PT_MQTT_WAIT_SEND(); } } } if(ev == mqtt_do_unsubscribe_event) { conn = data; DBG("MQTT - Got mqtt_do_unsubscribe_mqtt_event!\n"); if(conn->out_buffer_sent == 1 && conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) { PT_INIT(&conn->out_proto_thread); while(unsubscribe_pt(&conn->out_proto_thread, conn) < PT_EXITED && conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) { PT_MQTT_WAIT_SEND(); } } } if(ev == mqtt_do_publish_event) { conn = data; DBG("MQTT - Got mqtt_do_publish_mqtt_event!\n"); if(conn->out_buffer_sent == 1 && conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) { PT_INIT(&conn->out_proto_thread); while(publish_pt(&conn->out_proto_thread, conn) < PT_EXITED && conn->state == MQTT_CONN_STATE_CONNECTED_TO_BROKER) { PT_MQTT_WAIT_SEND(); } } } } PROCESS_END(); }
void mailcap_protocol_handler(struct connection *conn) { #ifdef HAVE_FORK unsigned char *script, *ref; pid_t pid; struct connection_state state = connection_state(S_OK); int pipe_read[2], check; /* security checks */ if (!conn->referrer || conn->referrer->protocol != PROTOCOL_MAILCAP) { goto bad; } ref = get_uri_string(conn->referrer, URI_DATA); if (!ref) { goto bad; } check = strcmp(ref, "elmailcap"); mem_free(ref); if (check) goto bad; script = get_uri_string(conn->uri, URI_DATA); if (!script) { state = connection_state(S_OUT_OF_MEM); goto end2; } if (c_pipe(pipe_read)) { state = connection_state_for_errno(errno); goto end1; } pid = fork(); if (pid < 0) { state = connection_state_for_errno(errno); goto end0; } if (!pid) { if (dup2(pipe_read[1], STDOUT_FILENO) < 0) { _exit(2); } /* We implicitly chain stderr to ELinks' stderr. */ close_all_non_term_fd(); if (execl("/bin/sh", "/bin/sh", "-c", script, (char *) NULL)) { _exit(3); } } else { /* ELinks */ mem_free(script); if (!init_http_connection_info(conn, 1, 0, 1)) { close(pipe_read[0]); close(pipe_read[1]); return; } close(pipe_read[1]); conn->socket->fd = pipe_read[0]; conn->data_socket->fd = -1; conn->cgi = 1; set_nonblocking_fd(conn->socket->fd); get_request(conn); return; } end0: close(pipe_read[0]); close(pipe_read[1]); end1: mem_free(script); end2: abort_connection(conn, state); return; #endif bad: abort_connection(conn, connection_state(S_BAD_URL)); }
void smb_protocol_handler(struct connection *conn) { int smb_pipe[2] = { -1, -1 }; int header_pipe[2] = { -1, -1 }; pid_t cpid; if (c_pipe(smb_pipe) || c_pipe(header_pipe)) { int s_errno = errno; if (smb_pipe[0] >= 0) close(smb_pipe[0]); if (smb_pipe[1] >= 0) close(smb_pipe[1]); if (header_pipe[0] >= 0) close(header_pipe[0]); if (header_pipe[1] >= 0) close(header_pipe[1]); abort_connection(conn, connection_state_for_errno(s_errno)); return; } conn->from = 0; conn->unrestartable = 1; find_auth(conn->uri); /* remember username and password */ cpid = fork(); if (cpid == -1) { int s_errno = errno; close(smb_pipe[0]); close(smb_pipe[1]); close(header_pipe[0]); close(header_pipe[1]); retry_connection(conn, connection_state_for_errno(s_errno)); return; } if (!cpid) { dup2(open("/dev/null", O_RDONLY), 0); close(1); close(2); data_out = fdopen(smb_pipe[1], "w"); header_out = fdopen(header_pipe[1], "w"); if (!data_out || !header_out) exit(1); close(smb_pipe[0]); close(header_pipe[0]); /* There may be outgoing data in stdio buffers * inherited from the parent process. The parent * process is going to write this data, so the child * process must not do that. Closing the file * descriptors ensures this. * * FIXME: If something opens more files and gets the * same file descriptors and does not close them * before exit(), then stdio may attempt to write the * buffers to the wrong files. This might happen for * example if libsmbclient calls syslog(). */ close_all_fds_but_two(smb_pipe[1], header_pipe[1]); do_smb(conn); } else { struct read_buffer *buf2; conn->data_socket->fd = smb_pipe[0]; conn->socket->fd = header_pipe[0]; set_nonblocking_fd(conn->data_socket->fd); set_nonblocking_fd(conn->socket->fd); close(smb_pipe[1]); close(header_pipe[1]); buf2 = alloc_read_buffer(conn->socket); if (!buf2) { close_socket(conn->data_socket); close_socket(conn->socket); abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } read_from_socket(conn->socket, buf2, connection_state(S_CONN), smb_got_header); } }
static void smb_got_header(struct socket *socket, struct read_buffer *rb) { struct connection *conn = socket->conn; struct read_buffer *buf; int error = 0; conn->cached = get_cache_entry(conn->uri); if (!conn->cached) { /* Even though these are pipes rather than real * sockets, call close_socket instead of close, to * ensure that abort_connection won't try to close the * file descriptors again. (Could we skip the calls * and assume abort_connection will do them?) */ close_socket(socket); close_socket(conn->data_socket); abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } socket->state = SOCKET_END_ONCLOSE; if (rb->length > 0) { unsigned char *ctype = memacpy(rb->data, rb->length); if (ctype && *ctype) { if (!strcmp(ctype, "text/x-error")) { error = 1; mem_free(ctype); } else { if (ctype[0] >= '0' && ctype[0] <= '9') { #ifdef HAVE_ATOLL conn->est_length = (off_t)atoll(ctype); #else conn->est_length = (off_t)atol(ctype); #endif mem_free(ctype); /* avoid error */ if (!conn->est_length) { abort_connection(conn, connection_state(S_OK)); return; } } else mem_free_set(&conn->cached->content_type, ctype); } } else { mem_free_if(ctype); } } buf = alloc_read_buffer(conn->data_socket); if (!buf) { close_socket(socket); close_socket(conn->data_socket); abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } if (error) { mem_free_set(&conn->cached->content_type, stracpy("text/html")); read_from_socket(conn->data_socket, buf, connection_state(S_CONN), smb_got_error); } else { read_from_socket(conn->data_socket, buf, connection_state(S_CONN), smb_got_data); } }
/* Kill the current connection and ask for a username/password for the next * try. */ static void prompt_username_pw(struct connection *conn) { add_auth_entry(conn->uri, "Samba", NULL, NULL, 0); abort_connection(conn, connection_state(S_OK)); }
void https_func(struct connection *c) { setcstate(c, S_NO_SSL); abort_connection(c); }
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 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); }
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; }
/* To reduce redundant error handling code [calls to abort_connection()] * most of the function is build around conditions that will assign the error * code to @state if anything goes wrong. The rest of the function will then just * do the necessary cleanups. If all works out we end up with @state being S_OK * resulting in a cache entry being created with the fragment data generated by * either reading the file content or listing a directory. */ void file_protocol_handler(struct connection *connection) { unsigned char *redirect_location = NULL; struct string page, name; struct connection_state state; int set_dir_content_type = 0; if (get_cmd_opt_bool((const unsigned char *)"anonymous")) { if (strcmp((const char *)connection->uri->string, "file:///dev/stdin") || isatty(STDIN_FILENO)) { abort_connection(connection, connection_state(S_FILE_ANONYMOUS)); return; } } #ifdef CONFIG_CGI if (!execute_cgi(connection)) return; #endif /* CONFIG_CGI */ /* Treat /dev/stdin in special way */ if (!strcmp((const char *)connection->uri->string, "file:///dev/stdin")) { int fd = open("/dev/stdin", O_RDONLY); if (fd == -1) { abort_connection(connection, connection_state(-errno)); return; } set_nonblocking_fd(fd); if (!init_http_connection_info(connection, 1, 0, 1)) { abort_connection(connection, connection_state(S_OUT_OF_MEM)); close(fd); return; } connection->socket->fd = fd; connection->data_socket->fd = -1; read_from_stdin(connection); return; } /* This function works on already simplified file-scheme URI pre-chewed * by transform_file_url(). By now, the function contains no hostname * part anymore, possibly relative path is converted to an absolute one * and uri->data is just the final path to file/dir we should try to * show. */ if (!init_string(&name) || !add_uri_to_string(&name, connection->uri, URI_PATH)) { done_string(&name); abort_connection(connection, connection_state(S_OUT_OF_MEM)); return; } decode_uri_string(&name); /* In Win32, file_is_dir seems to always return 0 if the name * ends with a directory separator. */ if ((name.length > 0 && dir_sep(name.source[name.length - 1])) || file_is_dir(name.source)) { /* In order for global history and directory listing to * function properly the directory url must end with a * directory separator. */ if (name.source[0] && !dir_sep(name.source[name.length - 1])) { redirect_location = (unsigned char *)STRING_DIR_SEP; state = connection_state(S_OK); } else { state = list_directory(connection, name.source, &page); set_dir_content_type = 1; } } else { state = read_encoded_file(&name, &page); /* FIXME: If state is now S_ENCODE_ERROR we should try loading * the file undecoded. --jonas */ } done_string(&name); if (is_in_state(state, S_OK)) { struct cache_entry *cached; /* Try to add fragment data to the connection cache if either * file reading or directory listing worked out ok. */ cached = connection->cached = get_cache_entry(connection->uri); if (!connection->cached) { if (!redirect_location) done_string(&page); state = connection_state(S_OUT_OF_MEM); } else if (redirect_location) { if (!redirect_cache(cached, redirect_location, 1, 0)) state = connection_state(S_OUT_OF_MEM); } else { add_fragment(cached, 0, page.source, page.length); connection->from += page.length; if (!cached->head && set_dir_content_type) { unsigned char *head; /* If the system charset somehow * changes after the directory listing * has been generated, it should be * parsed with the original charset. */ head = straconcat((const unsigned char *)"\r\nContent-Type: text/html; charset=", get_cp_mime_name(get_cp_index((const unsigned char *)"System")), "\r\n", (unsigned char *) NULL); /* Not so gracefully handle failed memory * allocation. */ if (!head) state = connection_state(S_OUT_OF_MEM); /* Setup directory listing for viewing. */ mem_free_set(&cached->head, head); } done_string(&page); } } abort_connection(connection, state); }
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; }