int httpSpecialRequest(ObjectPtr object, int method, int from, int to, HTTPRequestPtr requestor, void *closure) { char buffer[1024]; int hlen; if (method >= METHOD_POST) { return httpSpecialSideRequest(object, method, from, to, requestor, closure); } if (!(object->flags & OBJECT_INITIAL)) { privatiseObject(object, 0); supersedeObject(object); object->flags &= ~(OBJECT_VALIDATING | OBJECT_INPROGRESS); notifyObject(object); return 1; } hlen = snnprintf(buffer, 0, 1024, "\r\nServer: s_server" "\r\nContent-Type: text/html"); object->date = current_time.tv_sec; object->age = current_time.tv_sec; object->headers = internAtomN(buffer, hlen); object->code = 200; object->message = internAtom("Okay"); object->flags &= ~OBJECT_INITIAL; object->flags |= OBJECT_DYNAMIC; if (object->key_size == 8 && memcmp(object->key, "/s_server/", 8) == 0) { objectPrintf(object, 0, "<!DOCTYPE HTML PUBLIC " "\"-//W3C//DTD HTML 4.01 Transitional//EN\" " "\"http://www.w3.org/TR/html4/loose.dtd\">\n" "<html><head>\n" "<title>Polipo</title>\n" "</head><body>\n" "<h1>Polipo</h1>\n" "<p><a href=\"status?\">Status report</a>.</p>\n" "<p><a href=\"config?\">Current configuration</a>.</p>\n" "<p><a href=\"servers?\">Known servers</a>.</p>\n" #ifndef NO_DISK_CACHE "<p><a href=\"index?\">Disk cache index</a>.</p>\n" #endif "</body></html>\n"); object->length = object->size; } else if (matchUrl("/s_server/status", object)) { objectPrintf(object, 0, "<!DOCTYPE HTML PUBLIC " "\"-//W3C//DTD HTML 4.01 Transitional//EN\" " "\"http://www.w3.org/TR/html4/loose.dtd\">\n" "<html><head>\n" "<title>Polipo status report</title>\n" "</head><body>\n" "<h1>Polipo proxy on %s:%d: status report</h1>\n" "<p>The %s proxy on %s:%d is %s.</p>\n" "<p>There are %d public and %d private objects " "currently in memory using %d KB in %d chunks " "(%d KB allocated).</p>\n" "<p>There are %d atoms.</p>" "<p><form method=POST action=\"/s_server/status?\">" "<input type=submit name=\"init-forbidden\" " "value=\"Read forbidden file\"></form>\n" "<form method=POST action=\"/s_server/status?\">" "<input type=submit name=\"writeout-objects\" " "value=\"Write out in-memory cache\"></form>\n" "<form method=POST action=\"/s_server/status?\">" "<input type=submit name=\"discard-objects\" " "value=\"Discard in-memory cache\"></form>\n" "<form method=POST action=\"/s_server/status?\">" "<input type=submit name=\"reopen-log\" " "value=\"Reopen log file\"></form>\n" "<form method=POST action=\"/s_server/status?\">" "<input type=submit name=\"free-chunk-arenas\" " "value=\"Free chunk arenas\"></form></p>\n" "<p><a href=\"/s_server/\">back</a></p>" "</body></html>\n", proxyName->string, proxyPort, cacheIsShared ? "shared" : "private", proxyName->string, proxyPort, proxyOffline ? "off line" : (relaxTransparency ? "on line (transparency relaxed)" : "on line"), publicObjectCount, privateObjectCount, used_chunks * CHUNK_SIZE / 1024, used_chunks, totalChunkArenaSize() / 1024, used_atoms); object->expires = current_time.tv_sec; object->length = object->size; } else if (matchUrl("/s_server/config", object)) { fillSpecialObject(object, printConfig, NULL); object->expires = current_time.tv_sec + 5; #ifndef NO_DISK_CACHE } else if (matchUrl("/s_server/index", object)) { int len; char *root; if (disableIndexing) { abortObject(object, 403, internAtom("Action not allowed")); notifyObject(object); return 1; } len = MAX(0, object->key_size - 14); root = strdup_n((char *)object->key + 14, len); if (root == NULL) { abortObject(object, 503, internAtom("Couldn't allocate root")); notifyObject(object); return 1; } writeoutObjects(1); fillSpecialObject(object, plainIndexDiskObjects, root); free(root); object->expires = current_time.tv_sec + 5; } else if (matchUrl("/s_server/recursive-index", object)) { int len; char *root; if (disableIndexing) { abortObject(object, 403, internAtom("Action not allowed")); notifyObject(object); return 1; } len = MAX(0, object->key_size - 24); root = strdup_n((char *)object->key + 24, len); if (root == NULL) { abortObject(object, 503, internAtom("Couldn't allocate root")); notifyObject(object); return 1; } writeoutObjects(1); fillSpecialObject(object, recursiveIndexDiskObjects, root); free(root); object->expires = current_time.tv_sec + 20; #endif } else if (matchUrl("/s_server/servers", object)) { if (disableServersList) { abortObject(object, 403, internAtom("Action not allowed")); notifyObject(object); return 1; } fillSpecialObject(object, serversList, NULL); object->expires = current_time.tv_sec + 2; } else { abortObject(object, 404, internAtom("Not found")); } object->flags &= ~OBJECT_VALIDATING; notifyObject(object); return 1; }
int do_gethostbyname(char *origname, int count, int (*handler)(int, GethostbynameRequestPtr), void *data) { ObjectPtr object; int n = strlen(origname); AtomPtr name; GethostbynameRequestRec request; int done, rc; memset(&request, 0, sizeof(request)); request.name = NULL; request.addr = NULL; request.error_message = NULL; request.count = count; request.handler = handler; request.data = data; if(n <= 0 || n > 131) { if(n <= 0) { request.error_message = internAtom("empty name"); do_log(L_ERROR, "Empty DNS name.\n"); done = handler(-EINVAL, &request); } else { request.error_message = internAtom("name too long"); do_log(L_ERROR, "DNS name too long.\n"); done = handler(-ENAMETOOLONG, &request); } assert(done); releaseAtom(request.error_message); return 1; } if(origname[n - 1] == '.') n--; name = internAtomLowerN(origname, n); if(name == NULL) { request.error_message = internAtom("couldn't allocate name"); do_log(L_ERROR, "Couldn't allocate DNS name.\n"); done = handler(-ENOMEM, &request); assert(done); releaseAtom(request.error_message); return 1; } request.name = name; request.addr = NULL; request.error_message = NULL; request.count = count; request.object = NULL; request.handler = handler; request.data = data; object = findObject(OBJECT_DNS, name->string, name->length); if(object == NULL || objectMustRevalidate(object, NULL)) { if(object) { privatiseObject(object, 0); releaseObject(object); } object = makeObject(OBJECT_DNS, name->string, name->length, 1, 0, NULL, NULL); if(object == NULL) { request.error_message = internAtom("Couldn't allocate object"); do_log(L_ERROR, "Couldn't allocate DNS object.\n"); done = handler(-ENOMEM, &request); assert(done); releaseAtom(name); releaseAtom(request.error_message); return 1; } } if((object->flags & (OBJECT_INITIAL | OBJECT_INPROGRESS)) == OBJECT_INITIAL) { if(dnsUseGethostbyname >= 3) rc = really_do_gethostbyname(name, object); else rc = really_do_dns(name, object); if(rc < 0) { assert(!(object->flags & (OBJECT_INITIAL | OBJECT_INPROGRESS))); goto fail; } } if(dnsUseGethostbyname >= 3) assert(!(object->flags & OBJECT_INITIAL)); #ifndef NO_FANCY_RESOLVER if(object->flags & OBJECT_INITIAL) { ConditionHandlerPtr chandler; assert(object->flags & OBJECT_INPROGRESS); request.object = object; chandler = conditionWait(&object->condition, dnsHandler, sizeof(request), &request); if(chandler == NULL) goto fail; return 1; } #endif if(object->headers && object->headers->length > 0) { if(object->headers->string[0] == DNS_A) assert(((object->headers->length - 1) % sizeof(HostAddressRec)) == 0); else assert(object->headers->string[0] == DNS_CNAME); request.addr = retainAtom(object->headers); } else if(object->message) { request.error_message = retainAtom(object->message); } releaseObject(object); if(request.addr && request.addr->length > 0) done = handler(1, &request); else done = handler(-EDNS_HOST_NOT_FOUND, &request); assert(done); releaseAtom(request.addr); request.addr = NULL; releaseAtom(request.name); request.name = NULL; releaseAtom(request.error_message); request.error_message = NULL; return 1; fail: releaseNotifyObject(object); done = handler(-errno, &request); assert(done); releaseAtom(name); return 1; }