/* * Compare function for searching a conn by server string */ static int Capi_conn_by_server_cmp(const void *v1, const void *v2) { const capi_conn_t *node = v1; const char *server = v2; dReturn_val_if_fail(node && node->server && server, 1); return strcmp(node->server, server); }
/* * Change Content-Type for cache entry found by url. * from = { "http" | "meta" } * Return new content type. */ const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype, const char *from) { const char *curr; char *major, *minor, *charset; CacheEntry_t *entry = Cache_entry_search(url); dReturn_val_if_fail (entry != NULL, NULL); _MSG("a_Cache_set_content_type {%s} {%s}\n", ctype, URL_STR(url)); curr = Cache_current_content_type(entry); if (entry->TypeMeta || (*from == 'h' && entry->TypeHdr) ) { /* Type is already been set. Do nothing. * BTW, META overrides TypeHdr */ } else { if (*from == 'h') { /* Content-Type from HTTP header */ entry->TypeHdr = dStrdup(ctype); } else { /* Content-Type from META */ entry->TypeMeta = dStrdup(ctype); } if (a_Misc_content_type_cmp(curr, ctype)) { /* ctype gives one different from current */ a_Misc_parse_content_type(ctype, &major, &minor, &charset); if (*from == 'm' && charset && ((!major || !*major) && (!minor || !*minor))) { /* META only gives charset; use detected MIME type too */ entry->TypeNorm = dStrconcat(entry->TypeDet, ctype, NULL); } else if (*from == 'm' && !dStrnAsciiCasecmp(ctype, "text/xhtml", 10)) { /* WORKAROUND: doxygen uses "text/xhtml" in META */ entry->TypeNorm = dStrdup(entry->TypeDet); } if (charset) { if (entry->CharsetDecoder) a_Decode_free(entry->CharsetDecoder); entry->CharsetDecoder = a_Decode_charset_init(charset); curr = Cache_current_content_type(entry); /* Invalidate UTF8Data */ dStr_free(entry->UTF8Data, 1); entry->UTF8Data = NULL; } dFree(major); dFree(minor); dFree(charset); } } return curr; }
/* * Return a new string for the request used to tunnel HTTPS through a proxy. * As of 2009, the best reference appears to be section 5 of RFC 2817. */ char *a_Http_make_connect_str(const DilloUrl *url) { Dstr *dstr; const char *auth1; int auth_len; char *auth2, *proxy_auth, *retstr; dReturn_val_if_fail(Http_must_use_proxy(url), NULL); dstr = dStr_new(""); auth1 = URL_AUTHORITY(url); auth_len = strlen(auth1); if (auth_len > 0 && !isdigit(auth1[auth_len - 1])) /* if no port number, add HTTPS port */ auth2 = dStrconcat(auth1, ":443", NULL); else auth2 = dStrdup(auth1); proxy_auth = HTTP_Proxy_Auth_base64 ? dStrconcat ("Proxy-Authorization: Basic ", HTTP_Proxy_Auth_base64, "\r\n", NULL) : dStrdup(""); dStr_sprintfa( dstr, "CONNECT %s HTTP/1.1\r\n" "Host: %s\r\n" "%s" "\r\n", auth2, auth2, proxy_auth); dFree(auth2); dFree(proxy_auth); retstr = dstr->str; dStr_free(dstr, 0); return retstr; }
/* * Get a bit */ int a_Bitvec_get_bit(bitvec_t *bvec, int pos) { dReturn_val_if_fail (pos < bvec->len, 0); return (bvec->vec[pos/BVEC_SIZE] & 1 << pos % BVEC_SIZE); }
/* * Return the dpi server's port number, or -1 on error. * (A query is sent to dpid and then its answer parsed) * note: as the available servers and/or the dpi socket directory can * change at any time, we'll ask each time. If someday we find * that connecting each time significantly degrades performance, * an optimized approach can be tried. */ static int Dpi_get_server_port(const char *server_name) { int sock_fd = -1, dpi_port = -1; int dpid_port, ok = 0; struct sockaddr_in sin; char *cmd, *request, *rply = NULL, *port_str; socklen_t sin_sz; dReturn_val_if_fail (server_name != NULL, dpi_port); _MSG("Dpi_get_server_port:: server_name = [%s]\n", server_name); /* Read dpid's port from saved file */ if (Dpi_read_comm_keys(&dpid_port) != -1) { ok = 1; } if (ok) { /* Connect a socket with dpid */ ok = 0; sin_sz = sizeof(sin); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sin.sin_port = htons(dpid_port); if ((sock_fd = Dpi_make_socket_fd()) == -1 || connect(sock_fd, (struct sockaddr *)&sin, sin_sz) == -1) { MSG("Dpi_get_server_port: %s\n", dStrerror(errno)); } else { ok = 1; } } if (ok) { /* ask dpid to check the dpi and send its port number back */ ok = 0; request = a_Dpip_build_cmd("cmd=%s msg=%s", "check_server", server_name); _MSG("[%s]\n", request); if (Dpi_blocking_write(sock_fd, request, strlen(request)) == -1) { MSG("Dpi_get_server_port: %s\n", dStrerror(errno)); } else { ok = 1; } dFree(request); } if (ok) { /* Get the reply */ ok = 0; if ((rply = Dpi_blocking_read(sock_fd)) == NULL) { MSG("Dpi_get_server_port: can't read server port from dpid.\n"); } else { ok = 1; } } if (ok) { /* Parse reply */ ok = 0; cmd = a_Dpip_get_attr(rply, "cmd"); if (strcmp(cmd, "send_data") == 0) { port_str = a_Dpip_get_attr(rply, "msg"); _MSG("Dpi_get_server_port: rply=%s\n", rply); _MSG("Dpi_get_server_port: port_str=%s\n", port_str); dpi_port = strtol(port_str, NULL, 10); dFree(port_str); ok = 1; } dFree(cmd); } dFree(rply); Dpi_close_fd(sock_fd); return ok ? dpi_port : -1; }
/* * Receive new data, update the reception buffer (for next read), update the * cache, and service the client queue. * * This function gets called whenever the IO has new data. * 'Op' is the operation to perform * 'VPtr' is a (void) pointer to the IO control structure */ bool_t a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, const DilloUrl *Url) { int offset, len; const char *str; Dstr *dstr1, *dstr2, *dstr3; bool_t done = FALSE; CacheEntry_t *entry = Cache_entry_search(Url); /* Assert a valid entry (not aborted) */ dReturn_val_if_fail (entry != NULL, FALSE); _MSG("__a_Cache_process_dbuf__\n"); if (Op == IORead) { /* * Cache_get_header() will set CA_GotHeader if it has a full header, and * Cache_parse_header() will unset it if the header ends being * merely an informational response from the server (i.e., 100 Continue) */ for (offset = 0; !(entry->Flags & CA_GotHeader) && (len = Cache_get_header(entry, buf + offset, buf_size - offset)); Cache_parse_header(entry) ) { offset += len; } if (entry->Flags & CA_GotHeader) { str = buf + offset; len = buf_size - offset; entry->TransferSize += len; dstr1 = dstr2 = dstr3 = NULL; /* Decode arrived data (<= 3 stages) */ if (entry->TransferDecoder) { dstr1 = a_Decode_transfer_process(entry->TransferDecoder, str,len); done = a_Decode_transfer_finished(entry->TransferDecoder); str = dstr1->str; len = dstr1->len; } if (entry->ContentDecoder) { dstr2 = a_Decode_process(entry->ContentDecoder, str, len); str = dstr2->str; len = dstr2->len; } dStr_append_l(entry->Data, str, len); if (entry->CharsetDecoder && entry->UTF8Data) { dstr3 = a_Decode_process(entry->CharsetDecoder, str, len); dStr_append_l(entry->UTF8Data, dstr3->str, dstr3->len); } dStr_free(dstr1, 1); dStr_free(dstr2, 1); dStr_free(dstr3, 1); if (entry->Data->len) entry->Flags &= ~CA_IsEmpty; if ((entry->Flags & CA_GotLength) && (entry->TransferSize >= entry->ExpectedSize)) { done = TRUE; } if (!(entry->Flags & CA_KeepAlive)) { /* Let IOClose finish it later */ done = FALSE; } entry = Cache_process_queue(entry); if (entry && done) Cache_finish_msg(entry); } } else if (Op == IOClose) { Cache_finish_msg(entry); } else if (Op == IOAbort) { int i; CacheClient_t *Client; for (i = 0; (Client = dList_nth_data(ClientQueue, i)); ++i) { if (Client->Url == entry->Url) { DilloWeb *web = (DilloWeb *)Client->Web; a_Bw_remove_client(web->bw, Client->Key); Cache_client_dequeue(Client); --i; /* Keep the index value in the next iteration */ } } } return done; }