static bool fetch_resource_notfound_handler(struct fetch_resource_context *ctx) { fetch_msg msg; int code = 404; char buffer[1024]; const char *title; char key[8]; /* content is going to return error code */ fetch_set_http_code(ctx->fetchh, code); /* content type */ if (fetch_resource_send_header(ctx, "Content-Type: text/html")) goto fetch_resource_notfound_handler_aborted; snprintf(key, sizeof key, "HTTP%03d", code); title = messages_get(key); snprintf(buffer, sizeof buffer, "<html><head><title>%s</title></head>" "<body><h1>%s</h1>" "<p>Error %d while fetching file %s</p></body></html>", title, title, code, nsurl_access(ctx->url)); msg.type = FETCH_DATA; msg.data.header_or_data.buf = (const uint8_t *) buffer; msg.data.header_or_data.len = strlen(buffer); if (fetch_resource_send_callback(&msg, ctx)) goto fetch_resource_notfound_handler_aborted; msg.type = FETCH_FINISHED; fetch_resource_send_callback(&msg, ctx); fetch_resource_notfound_handler_aborted: return false; }
static bool fetch_about_blank_handler(struct fetch_about_context *ctx) { fetch_msg msg; const char buffer[2] = { ' ', '\0' }; /* content is going to return ok */ fetch_set_http_code(ctx->fetchh, 200); /* content type */ if (fetch_about_send_header(ctx, "Content-Type: text/html")) goto fetch_about_blank_handler_aborted; msg.type = FETCH_DATA; msg.data.header_or_data.buf = (const uint8_t *) buffer; msg.data.header_or_data.len = strlen(buffer); if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_blank_handler_aborted; msg.type = FETCH_FINISHED; fetch_about_send_callback(&msg, ctx); return true; fetch_about_blank_handler_aborted: return false; }
/** * Find the status code and content type and inform the caller. * * Return true if the fetch is being aborted. */ static bool fetch_curl_process_headers(struct curl_fetch_info *f) { long http_code; CURLcode code; fetch_msg msg; f->had_headers = true; if (!f->http_code) { code = curl_easy_getinfo(f->curl_handle, CURLINFO_HTTP_CODE, &f->http_code); fetch_set_http_code(f->fetch_handle, f->http_code); assert(code == CURLE_OK); } http_code = f->http_code; LOG("HTTP status code %li", http_code); if (http_code == 304 && !f->post_urlenc && !f->post_multipart) { /* Not Modified && GET request */ msg.type = FETCH_NOTMODIFIED; fetch_send_callback(&msg, f->fetch_handle); return true; } /* handle HTTP redirects (3xx response codes) */ if (300 <= http_code && http_code < 400 && f->location != 0) { LOG("FETCH_REDIRECT, '%s'", f->location); msg.type = FETCH_REDIRECT; msg.data.redirect = f->location; fetch_send_callback(&msg, f->fetch_handle); return true; } /* handle HTTP 401 (Authentication errors) */ if (http_code == 401) { msg.type = FETCH_AUTH; msg.data.auth.realm = f->realm; fetch_send_callback(&msg, f->fetch_handle); return true; } /* handle HTTP errors (non 2xx response codes) */ if (f->only_2xx && strncmp(nsurl_access(f->url), "http", 4) == 0 && (http_code < 200 || 299 < http_code)) { msg.type = FETCH_ERROR; msg.data.error = messages_get("Not2xx"); fetch_send_callback(&msg, f->fetch_handle); return true; } if (f->abort) return true; return false; }
/** Generate the text of a Choices file which represents the current * in use options. */ static bool fetch_about_choices_handler(struct fetch_about_context *ctx) { fetch_msg msg; char buffer[1024]; int code = 200; int slen; unsigned int opt_loop = 0; int res = 0; /* content is going to return ok */ fetch_set_http_code(ctx->fetchh, code); /* content type */ if (fetch_about_send_header(ctx, "Content-Type: text/plain")) goto fetch_about_choices_handler_aborted; msg.type = FETCH_DATA; msg.data.header_or_data.buf = (const uint8_t *) buffer; slen = snprintf(buffer, sizeof buffer, "# Automatically generated current NetSurf browser Choices\n"); do { res = nsoption_snoptionf(buffer + slen, sizeof buffer - slen, opt_loop, "%k:%v\n"); if (res <= 0) break; /* last option */ if (res >= (int) (sizeof buffer - slen)) { /* last entry would not fit in buffer, submit buffer */ msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_choices_handler_aborted; slen = 0; } else { /* normal addition */ slen += res; opt_loop++; } } while (res > 0); msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_choices_handler_aborted; msg.type = FETCH_FINISHED; fetch_about_send_callback(&msg, ctx); return true; fetch_about_choices_handler_aborted: return false; }
/** * called from poll to progress fetch. * * \todo This is currently completely unimplemented and just returns 204 */ static bool fetch_javascript_handler(struct fetch_javascript_context *ctx) { fetch_msg msg; int code = 204; /* content is going to return error code */ fetch_set_http_code(ctx->fetchh, code); msg.type = FETCH_FINISHED; fetch_javascript_send_callback(&msg, ctx); return true; }
static bool fetch_resource_redirect_handler(struct fetch_resource_context *ctx) { fetch_msg msg; /* content is going to return redirect */ fetch_set_http_code(ctx->fetchh, 302); msg.type = FETCH_REDIRECT; msg.data.redirect = nsurl_access(ctx->redirect_url); fetch_resource_send_callback(&msg, ctx); return true; }
static bool fetch_about_welcome_handler(struct fetch_about_context *ctx) { fetch_msg msg; /* content is going to return redirect */ fetch_set_http_code(ctx->fetchh, 302); msg.type = FETCH_REDIRECT; msg.data.redirect = "resource:welcome.html"; fetch_about_send_callback(&msg, ctx); return true; }
/** * Callback function for cURL. */ static size_t fetch_curl_data(char *data, size_t size, size_t nmemb, void *_f) { struct curl_fetch_info *f = _f; CURLcode code; fetch_msg msg; /* ensure we only have to get this information once */ if (!f->http_code) { code = curl_easy_getinfo(f->curl_handle, CURLINFO_HTTP_CODE, &f->http_code); fetch_set_http_code(f->fetch_handle, f->http_code); assert(code == CURLE_OK); } /* ignore body if this is a 401 reply by skipping it and reset * the HTTP response code to enable follow up fetches. */ if (f->http_code == 401) { f->http_code = 0; return size * nmemb; } if (f->abort || (!f->had_headers && fetch_curl_process_headers(f))) { f->stopped = true; return 0; } /* send data to the caller */ msg.type = FETCH_DATA; msg.data.header_or_data.buf = (const uint8_t *) data; msg.data.header_or_data.len = size * nmemb; fetch_send_callback(&msg, f->fetch_handle); if (f->abort) { f->stopped = true; return 0; } return size * nmemb; }
static void fetch_rsrc_poll(lwc_string *scheme) { fetch_msg msg; struct fetch_rsrc_context *c, *next; if (ring == NULL) return; /* Iterate over ring, processing each pending fetch */ c = ring; do { /* Take a copy of the next pointer as we may destroy * the ring item we're currently processing */ next = c->r_next; /* Ignore fetches that have been flagged as locked. * This allows safe re-entrant calls to this function. * Re-entrancy can occur if, as a result of a callback, * the interested party causes fetch_poll() to be called * again. */ if (c->locked == true) { continue; } /* Only process non-aborted fetches */ if (!c->aborted && fetch_rsrc_process(c) == true) { char header[64]; fetch_set_http_code(c->parent_fetch, 200); LOG(("setting rsrc: MIME type to %s, length to %zd", c->mimetype, c->datalen)); /* Any callback can result in the fetch being aborted. * Therefore, we _must_ check for this after _every_ * call to fetch_rsrc_send_callback(). */ snprintf(header, sizeof header, "Content-Type: %s", c->mimetype); msg.type = FETCH_HEADER; msg.data.header_or_data.buf = (const uint8_t *) header; msg.data.header_or_data.len = strlen(header); fetch_rsrc_send_callback(&msg, c); snprintf(header, sizeof header, "Content-Length: %zd", c->datalen); msg.type = FETCH_HEADER; msg.data.header_or_data.buf = (const uint8_t *) header; msg.data.header_or_data.len = strlen(header); fetch_rsrc_send_callback(&msg, c); if (!c->aborted) { msg.type = FETCH_DATA; msg.data.header_or_data.buf = (const uint8_t *) c->data; msg.data.header_or_data.len = c->datalen; fetch_rsrc_send_callback(&msg, c); } if (!c->aborted) { msg.type = FETCH_FINISHED; fetch_rsrc_send_callback(&msg, c); } } else { LOG(("Processing of %s failed!", c->url)); /* Ensure that we're unlocked here. If we aren't, * then fetch_rsrc_process() is broken. */ assert(c->locked == false); } fetch_remove_from_queues(c->parent_fetch); fetch_free(c->parent_fetch); /* Advance to next ring entry, exiting if we've reached * the start of the ring or the ring has become empty */ } while ( (c = next) != ring && ring != NULL); }
void ami_fetch_file_poll(const char *scheme_ignored) { struct nsObject *node; struct nsObject *nnode; struct ami_file_fetch_info *fetch; fetch_error_code errorcode; if(IsMinListEmpty(ami_file_fetcher_list)) return; node = (struct nsObject *)GetHead((struct List *)ami_file_fetcher_list); do { errorcode = FETCH_ERROR_NO_ERROR; nnode=(struct nsObject *)GetSucc((struct Node *)node); fetch = (struct ami_file_fetch_info *)node->objstruct; if(fetch->locked) continue; if(!fetch->aborted) { if(fetch->fh) { ULONG len; len = FRead(fetch->fh,ami_file_fetcher_buffer,1,1024); if (len == (ULONG)-1) errorcode = FETCH_ERROR_MISC; else if (len > 0) ami_fetch_file_send_callback( FETCH_DATA, fetch, ami_file_fetcher_buffer, len, errorcode); if((len<1024) && (!fetch->aborted)) { ami_fetch_file_send_callback(FETCH_FINISHED, fetch, NULL, 0, errorcode); fetch->aborted = true; } } else { fetch->fh = FOpen(fetch->path,MODE_OLDFILE,0); if(fetch->fh) { char header[64]; struct ExamineData *fib; if(fib = ExamineObjectTags(EX_FileHandleInput,fetch->fh,TAG_DONE)) { fetch->len = fib->FileSize; FreeDosObject(DOS_EXAMINEDATA,fib); } fetch_set_http_code(fetch->fetch_handle,200); fetch->mimetype = fetch_mimetype(fetch->path); LOG(("mimetype %s len %ld",fetch->mimetype,fetch->len)); snprintf(header, sizeof header, "Content-Type: %s", fetch->mimetype); ami_fetch_file_send_callback(FETCH_HEADER, fetch, header, strlen(header), errorcode); snprintf(header, sizeof header, "Content-Length: %ld", fetch->len); ami_fetch_file_send_callback(FETCH_HEADER, fetch, header, strlen(header), errorcode); } else { STRPTR errorstring; errorstring = ASPrintf("%s %s",messages_get("FileError"),fetch->path); fetch_set_http_code(fetch->fetch_handle,404); errorcode = FETCH_ERROR_HTTP_NOT2; ami_fetch_file_send_callback(FETCH_ERROR, fetch, errorstring, 0, errorcode); fetch->aborted = true; FreeVec(errorstring); } } } if(fetch && fetch->aborted) { fetch_remove_from_queues(fetch->fetch_handle); fetch_free(fetch->fetch_handle); return; } }while(node=nnode); }
/** * List all the valid about: paths available * * \param ctx The fetch context. * \return true for sucess or false to generate an error. */ static bool fetch_about_about_handler(struct fetch_about_context *ctx) { fetch_msg msg; char buffer[1024]; int code = 200; int slen; unsigned int abt_loop = 0; int res = 0; /* content is going to return ok */ fetch_set_http_code(ctx->fetchh, code); /* content type */ if (fetch_about_send_header(ctx, "Content-Type: text/html")) goto fetch_about_config_handler_aborted; msg.type = FETCH_DATA; msg.data.header_or_data.buf = (const uint8_t *) buffer; slen = snprintf(buffer, sizeof buffer, "<html>\n<head>\n" "<title>NetSurf List of About pages</title>\n" "<link rel=\"stylesheet\" type=\"text/css\" " "href=\"resource:internal.css\">\n" "</head>\n" "<body id =\"aboutlist\">\n" "<p class=\"banner\">" "<a href=\"http://www.netsurf-browser.org/\">" "<img src=\"resource:netsurf.png\" alt=\"NetSurf\"></a>" "</p>\n" "<h1>NetSurf List of About pages</h1>\n" "<ul>\n"); for (abt_loop = 0; abt_loop < about_handler_list_len; abt_loop++) { /* Skip over hidden entries */ if (about_handler_list[abt_loop].hidden) continue; res = snprintf(buffer + slen, sizeof buffer - slen, "<li><a href=\"about:%s\">about:%s</a></li>\n", about_handler_list[abt_loop].name, about_handler_list[abt_loop].name); if (res <= 0) break; /* last option */ if (res >= (int)(sizeof buffer - slen)) { /* last entry would not fit in buffer, submit buffer */ msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_config_handler_aborted; slen = 0; } else { /* normal addition */ slen += res; } } slen += snprintf(buffer + slen, sizeof buffer - slen, "</ul>\n</body>\n</html>\n"); msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_config_handler_aborted; msg.type = FETCH_FINISHED; fetch_about_send_callback(&msg, ctx); return true; fetch_about_config_handler_aborted: return false; }
static bool fetch_about_testament_handler(struct fetch_about_context *ctx) { static modification_t modifications[] = WT_MODIFICATIONS; fetch_msg msg; char buffer[1024]; int code = 200; int slen; int i; /* content is going to return ok */ fetch_set_http_code(ctx->fetchh, code); /* content type */ if (fetch_about_send_header(ctx, "Content-Type: text/plain")) goto fetch_about_testament_handler_aborted; msg.type = FETCH_DATA; msg.data.header_or_data.buf = (const uint8_t *) buffer; slen = snprintf(buffer, sizeof buffer, "# Automatically generated by NetSurf build system\n\n"); msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_testament_handler_aborted; slen = snprintf(buffer, sizeof buffer, #if defined(WT_BRANCHISTRUNK) || defined(WT_BRANCHISMASTER) "# This is a *DEVELOPMENT* build from the main line.\n\n" #elif defined(WT_BRANCHISTAG) && (WT_MODIFIED == 0) "# This is a tagged build of NetSurf\n" #ifdef WT_TAGIS "# The tag used was '" WT_TAGIS "'\n\n" #else "\n" #endif #elif defined(WT_NO_SVN) || defined(WT_NO_GIT) "# This NetSurf was built outside of our revision " "control environment.\n" "# This testament is therefore very useful.\n\n" #else "# This NetSurf was built from a branch (" WT_BRANCHPATH ").\n\n" #endif #if defined(CI_BUILD) "# This build carries the CI build number '" CI_BUILD "'\n\n" #endif ); msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_testament_handler_aborted; slen = snprintf(buffer, sizeof buffer, "Built by %s (%s) from %s at revision %s\n\n", GECOS, USERNAME, WT_BRANCHPATH, WT_REVID); msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_testament_handler_aborted; slen = snprintf(buffer, sizeof buffer, "Built on %s in %s\n\n", WT_HOSTNAME, WT_ROOT); msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_testament_handler_aborted; if (WT_MODIFIED > 0) { slen = snprintf(buffer, sizeof buffer, "Working tree has %d modification%s\n\n", WT_MODIFIED, WT_MODIFIED == 1 ? "" : "s"); } else { slen = snprintf(buffer, sizeof buffer, "Working tree is not modified.\n"); } msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_testament_handler_aborted; for (i = 0; i < WT_MODIFIED; ++i) { slen = snprintf(buffer, sizeof buffer, " %s %s\n", modifications[i].modtype, modifications[i].leaf); msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_testament_handler_aborted; } msg.type = FETCH_FINISHED; fetch_about_send_callback(&msg, ctx); return true; fetch_about_testament_handler_aborted: return false; }
/** Handler to generate about:config page */ static bool fetch_about_config_handler(struct fetch_about_context *ctx) { fetch_msg msg; char buffer[1024]; int code = 200; int slen; unsigned int opt_loop = 0; int res = 0; /* content is going to return ok */ fetch_set_http_code(ctx->fetchh, code); /* content type */ if (fetch_about_send_header(ctx, "Content-Type: text/html")) goto fetch_about_config_handler_aborted; msg.type = FETCH_DATA; msg.data.header_or_data.buf = (const uint8_t *) buffer; slen = snprintf(buffer, sizeof buffer, "<html>\n<head>\n" "<title>NetSurf Browser Config</title>\n" "<link rel=\"stylesheet\" type=\"text/css\" " "href=\"resource:internal.css\">\n" "</head>\n" "<body id =\"configlist\">\n" "<p class=\"banner\">" "<a href=\"http://www.netsurf-browser.org/\">" "<img src=\"resource:netsurf.png\" alt=\"NetSurf\"></a>" "</p>\n" "<h1>NetSurf Browser Config</h1>\n" "<table class=\"config\">\n" "<tr><th></th><th></th><th></th></tr>\n"); do { res = nsoption_snoptionf(buffer + slen, sizeof buffer - slen, opt_loop, "<tr><th>%k</th><td>%t</td><td>%V</td></tr>\n"); if (res <= 0) break; /* last option */ if (res >= (int) (sizeof buffer - slen)) { /* last entry would not fit in buffer, submit buffer */ msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_config_handler_aborted; slen = 0; } else { /* normal addition */ slen += res; opt_loop++; } } while (res > 0); slen += snprintf(buffer + slen, sizeof buffer - slen, "</table>\n</body>\n</html>\n"); msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_config_handler_aborted; msg.type = FETCH_FINISHED; fetch_about_send_callback(&msg, ctx); return true; fetch_about_config_handler_aborted: return false; }
/** Handler to generate about:cache page. * * Shows details of current iamge cache * */ static bool fetch_about_imagecache_handler(struct fetch_about_context *ctx) { fetch_msg msg; char buffer[2048]; /* output buffer */ int code = 200; int slen; unsigned int cent_loop = 0; int res = 0; /* content is going to return ok */ fetch_set_http_code(ctx->fetchh, code); /* content type */ if (fetch_about_send_header(ctx, "Content-Type: text/html")) goto fetch_about_imagecache_handler_aborted; msg.type = FETCH_DATA; msg.data.header_or_data.buf = (const uint8_t *) buffer; /* page head */ slen = snprintf(buffer, sizeof buffer, "<html>\n<head>\n" "<title>NetSurf Browser Image Cache Status</title>\n" "<link rel=\"stylesheet\" type=\"text/css\" " "href=\"resource:internal.css\">\n" "</head>\n" "<body id =\"cachelist\">\n" "<p class=\"banner\">" "<a href=\"http://www.netsurf-browser.org/\">" "<img src=\"resource:netsurf.png\" alt=\"NetSurf\"></a>" "</p>\n" "<h1>NetSurf Browser Image Cache Status</h1>\n" ); msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_imagecache_handler_aborted; /* image cache summary */ slen = image_cache_snsummaryf(buffer, sizeof(buffer), "<p>Configured limit of %a hysteresis of %b</p>\n" "<p>Total bitmap size in use %c (in %d)</p>\n" "<p>Age %es</p>\n" "<p>Peak size %f (in %g)</p>\n" "<p>Peak image count %h (size %i)</p>\n" "<p>Cache total/hit/miss/fail (counts) %j/%k/%l/%m " "(%pj%%/%pk%%/%pl%%/%pm%%)</p>\n" "<p>Cache total/hit/miss/fail (size) %n/%o/%q/%r " "(%pn%%/%po%%/%pq%%/%pr%%)</p>\n" "<p>Total images never rendered: %s " "(includes %t that were converted)</p>\n" "<p>Total number of excessive conversions: %u " "(from %v images converted more than once)" "</p>\n" "<p>Bitmap of size %w had most (%x) conversions</p>\n" "<h2>Current image cache contents</h2>\n"); if (slen >= (int) (sizeof(buffer))) goto fetch_about_imagecache_handler_aborted; /* overflow */ msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_imagecache_handler_aborted; /* image cache entry table */ slen = snprintf(buffer, sizeof buffer, "<p class=\"imagecachelist\">\n" "<strong>" "<span>Entry</span>" "<span>Content Key</span>" "<span>Redraw Count</span>" "<span>Conversion Count</span>" "<span>Last Redraw</span>" "<span>Bitmap Age</span>" "<span>Bitmap Size</span>" "<span>Source</span>" "</strong>\n"); do { res = image_cache_snentryf(buffer + slen, sizeof buffer - slen, cent_loop, "<a href=\"%U\">" "<span>%e</span>" "<span>%k</span>" "<span>%r</span>" "<span>%c</span>" "<span>%a</span>" "<span>%g</span>" "<span>%s</span>" "<span>%o</span>" "</a>\n"); if (res <= 0) break; /* last option */ if (res >= (int) (sizeof buffer - slen)) { /* last entry would not fit in buffer, submit buffer */ msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_imagecache_handler_aborted; slen = 0; } else { /* normal addition */ slen += res; cent_loop++; } } while (res > 0); slen += snprintf(buffer + slen, sizeof buffer - slen, "</p>\n</body>\n</html>\n"); msg.data.header_or_data.len = slen; if (fetch_about_send_callback(&msg, ctx)) goto fetch_about_imagecache_handler_aborted; msg.type = FETCH_FINISHED; fetch_about_send_callback(&msg, ctx); return true; fetch_about_imagecache_handler_aborted: return false; }