unsigned char *translate_url(unsigned char *url, unsigned char *cwd) { unsigned char *ch; unsigned char *nu, *da; unsigned char *prefix; int sl; while (*url == ' ') url++; if (*url && url[strlen(cast_const_char url) - 1] == ' ') { nu = stracpy(url); while (*nu && nu[strlen(cast_const_char nu) - 1] == ' ') nu[strlen(cast_const_char nu) - 1] = 0; ch = translate_url(nu, cwd); mem_free(nu); return ch; } if (!casecmp(cast_uchar "proxy://", url, 8)) return NULL; if (!parse_url(url, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &da, NULL, NULL)) { nu = stracpy(url); goto return_nu; } if (strchr(cast_const_char url, POST_CHAR)) return NULL; if (strstr(cast_const_char url, "://")) { nu = stracpy(url); extend_str(&nu, 1); ch = cast_uchar strrchr(cast_const_char nu, '#'); if (!ch || strchr(cast_const_char ch, '/')) ch = nu + strlen(cast_const_char nu); memmove(ch + 1, ch, strlen(cast_const_char ch) + 1); *ch = '/'; if (!parse_url(nu, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) goto return_nu; mem_free(nu); } prefix = cast_uchar "file://"; if (url[0] == '[' && strchr(cast_const_char url, ']')) { ch = url; goto http; } ch = url + strcspn(cast_const_char url, ".:/@"); sl = 0; #ifdef SPAD if (strchr(cast_const_char url, ':') && _is_local(cast_const_char url)) goto set_prefix; #endif if (*ch != ':' || *(url + strcspn(cast_const_char url, "/@")) == '@') { if (*url != '.' && *ch == '.') { unsigned char *e, *f, *g; int tl; for (e = ch + 1; *(f = e + strcspn(cast_const_char e, ".:/")) == '.'; e = f + 1) ; g = memacpy(e, f - e); tl = is_tld(g); mem_free(g); if (tl) http: prefix = cast_uchar "http://", sl = 1; } if (*ch == '@' || *ch == ':' || !cmpbeg(url, cast_uchar "ftp.")) prefix = cast_uchar "ftp://", sl = 1; goto set_prefix; set_prefix: nu = stracpy(prefix); add_to_strn(&nu, url); if (sl && !strchr(cast_const_char url, '/')) add_to_strn(&nu, cast_uchar "/"); if (parse_url(nu, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { mem_free(nu); return NULL; } goto return_nu; } #ifdef DOS_FS if (ch == url + 1) goto set_prefix; #endif if (!(nu = memacpy(url, ch - url + 1))) return NULL; add_to_strn(&nu, cast_uchar "//"); add_to_strn(&nu, ch + 1); if (!parse_url(nu, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) goto return_nu; add_to_strn(&nu, cast_uchar "/"); if (!parse_url(nu, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) goto return_nu; mem_free(nu); return NULL; return_nu: insert_wd(&nu, cwd); extend_str(&nu, 1); translate_directories(nu); nu = translate_hashbang(nu); return nu; }
unsigned char *translate_url(unsigned char *url, unsigned char *cwd) { unsigned char *ch; unsigned char *nu, *da; unsigned char *prefix; int sl; while (*url == ' ') url++; if (*url && url[strlen(cast_const_char url) - 1] == ' ') { nu = stracpy(url); while (*nu && nu[strlen(cast_const_char nu) - 1] == ' ') nu[strlen(cast_const_char nu) - 1] = 0; ch = translate_url(nu, cwd); mem_free(nu); return ch; } if (!casecmp(cast_uchar "proxy://", url, 8)) return NULL; if (!parse_url(url, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &da, NULL, NULL)) { nu = stracpy(url); goto return_nu; } if (strchr(cast_const_char url, POST_CHAR)) return NULL; if (strstr(cast_const_char url, "://")) { nu = stracpy(url); extend_str(&nu, 1); ch = cast_uchar strrchr(cast_const_char nu, '#'); if (!ch || strchr(cast_const_char ch, '/')) ch = nu + strlen(cast_const_char nu); memmove(ch + 1, ch, strlen(cast_const_char ch) + 1); *ch = '/'; if (!parse_url(nu, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) goto return_nu; mem_free(nu); } prefix = cast_uchar "file://"; if (url[0] == '[' && strchr(cast_const_char url, ']')) { ch = url; goto http; } ch = url + strcspn(cast_const_char url, ".:/@"); sl = 0; #ifdef SPAD if (strchr(cast_const_char url, ':') && _is_local(cast_const_char url)) goto set_prefix; #endif if (*ch != ':' || *(url + strcspn(cast_const_char url, "/@")) == '@') { if (*url != '.' && *ch == '.') { unsigned char *f, *e; int i; for (e = ch + 1; *(f = e + strcspn(cast_const_char e, ".:/")) == '.'; e = f + 1) ; for (i = 0; i < f - e; i++) if (e[i] < '0' || e[i] > '9') goto noip; goto http; noip: if (f - e == 2 && casecmp(e, cast_uchar "gz", 2)) { http: prefix = cast_uchar "http://", sl = 1; } else { char *tld[] = { "com", "edu", "net", "org", "gov", "mil", "int", "arpa", "aero", "biz", "coop", "info", "museum", "name", "pro", "cat", "jobs", "mobi", "travel", "tel", "onion", "exit", NULL }; for (i = 0; tld[i]; i++) if ((size_t)(f - e) == strlen(cast_const_char tld[i]) && !casecmp(cast_uchar tld[i], e, f - e)) goto http; } } if (*ch == '@' || *ch == ':' || !cmpbeg(url, cast_uchar "ftp.")) prefix = cast_uchar "ftp://", sl = 1; goto set_prefix; set_prefix: nu = stracpy(prefix); add_to_strn(&nu, url); if (sl && !strchr(cast_const_char url, '/')) add_to_strn(&nu, cast_uchar "/"); if (parse_url(nu, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { mem_free(nu); return NULL; } goto return_nu; } #ifdef DOS_FS if (ch == url + 1) goto set_prefix; #endif if (!(nu = memacpy(url, ch - url + 1))) return NULL; add_to_strn(&nu, cast_uchar "//"); add_to_strn(&nu, ch + 1); if (!parse_url(nu, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) goto return_nu; add_to_strn(&nu, cast_uchar "/"); if (!parse_url(nu, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) goto return_nu; mem_free(nu); return NULL; return_nu: insert_wd(&nu, cwd); extend_str(&nu, 1); translate_directories(nu); nu = translate_hashbang(nu); return nu; }
/* * U funkce join_urls musi byt prvni url absolutni (takove, co projde funkci * parse_url bez chyby --- pokud neni absolutni, tak to spatne na internal) a * druhe url je relativni cesta vuci nemu nebo taky absolutni url. Pokud je * druhe url absolutni, vrati se to; pokud je relativni, tak se spoji prvni a * druhe url. */ unsigned char *join_urls(unsigned char *base, unsigned char *rel) { unsigned char *p, *n, *pp, *ch; int l; int lo = !casecmp(base, cast_uchar "file://", 7); int data = !casecmp(base, cast_uchar "data:", 5); if (rel[0] == '#' || !rel[0]) { n = stracpy(base); for (p = n; *p && *p != POST_CHAR && *p != '#'; p++) ; *p = 0; add_to_strn(&n, rel); goto return_n; } if (rel[0] == '?' || rel[0] == '&') { unsigned char rj[3]; unsigned char *d = get_url_data(base); if (!d) goto bad_base; rj[0] = rel[0]; rj[1] = POST_CHAR; rj[2] = 0; d += strcspn(cast_const_char d, cast_const_char rj); n = memacpy(base, d - base); add_to_strn(&n, rel); goto return_n; } if (rel[0] == '/' && rel[1] == '/' && !data) { unsigned char *s; if (!(s = cast_uchar strstr(cast_const_char base, "//"))) { if (!(s = cast_uchar strchr(cast_const_char base, ':'))) { bad_base: internal("bad base url: %s", base); return NULL; } s++; } n = memacpy(base, s - base); add_to_strn(&n, rel); if (!parse_url(n, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) goto return_n; add_to_strn(&n, cast_uchar "/"); if (!parse_url(n, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) goto return_n; mem_free(n); } if (!casecmp(cast_uchar "proxy://", rel, 8)) goto prx; if (!parse_url(rel, &l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) { n = stracpy(rel); goto return_n; } n = stracpy(rel); while (n[0] && n[strlen(cast_const_char n) - 1] <= ' ') n[strlen(cast_const_char n) - 1] = 0; extend_str(&n, 1); ch = cast_uchar strrchr(cast_const_char n, '#'); if (!ch || strchr(cast_const_char ch, '/')) ch = n + strlen(cast_const_char n); memmove(ch + 1, ch, strlen(cast_const_char ch) + 1); *ch = '/'; if (!parse_url(n, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)) goto return_n; mem_free(n); prx: if (parse_url(base, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &p, NULL, NULL) || !p) { goto bad_base; } if (!dsep(*p)) p--; if (!data) { if (end_of_dir(base, rel[0])) for (; *p; p++) { if (end_of_dir(base, *p)) break; } else if (!dsep(rel[0])) for (pp = p; *pp; pp++) { if (end_of_dir(base, *pp)) break; if (dsep(*pp)) p = pp + 1; } } n = memacpy(base, p - base); add_to_strn(&n, rel); goto return_n; return_n: extend_str(&n, 1); translate_directories(n); return n; }
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); }