/** * Create a path from a nsurl using amiga file handling. * * @param[in] url The url to encode. * @param[out] path_out A string containing the result path which should * be freed by the caller. * @return NSERROR_OK and the path is written to \a path or error code * on faliure. */ static nserror amiga_nsurl_to_path(struct nsurl *url, char **path_out) { lwc_string *urlpath; char *path; bool match; lwc_string *scheme; nserror res; char *colon; char *slash; if ((url == NULL) || (path_out == NULL)) { return NSERROR_BAD_PARAMETER; } scheme = nsurl_get_component(url, NSURL_SCHEME); if (lwc_string_caseless_isequal(scheme, corestring_lwc_file, &match) != lwc_error_ok) { return NSERROR_BAD_PARAMETER; } lwc_string_unref(scheme); if (match == false) { return NSERROR_BAD_PARAMETER; } urlpath = nsurl_get_component(url, NSURL_PATH); if (urlpath == NULL) { return NSERROR_BAD_PARAMETER; } res = url_unescape(lwc_string_data(urlpath) + 1, &path); lwc_string_unref(urlpath); if (res != NSERROR_OK) { return res; } colon = strchr(path, ':'); if(colon == NULL) { slash = strchr(path, '/'); if(slash) { *slash = ':'; } else { int len = strlen(path); path[len] = ':'; path[len + 1] = '\0'; } } *path_out = path; return NSERROR_OK; }
/** * Try and find the correct RISC OS filetype from a download context. */ static nserror download_ro_filetype(download_context *ctx, bits *ftype_out) { nsurl *url = download_context_get_url(ctx); bits ftype = 0; lwc_string *scheme; /* If the file is local try and read its filetype */ scheme = nsurl_get_component(url, NSURL_SCHEME); if (scheme != NULL) { bool filescheme; if (lwc_string_isequal(scheme, corestring_lwc_file, &filescheme) != lwc_error_ok) { filescheme = false; } if (filescheme) { lwc_string *path = nsurl_get_component(url, NSURL_PATH); if (path != NULL && lwc_string_length(path) != 0) { char *raw_path; if (url_unescape(lwc_string_data(path), lwc_string_length(path), &raw_path) == NSERROR_OK) { ftype = ro_filetype_from_unix_path(raw_path); free(raw_path); } } } } /* If we still don't have a filetype (i.e. failed reading local * one or fetching a remote object), then use the MIME type. */ if (ftype == 0) { /* convert MIME type to RISC OS file type */ os_error *error; const char *mime_type; mime_type = download_context_get_mime_type(ctx); error = xmimemaptranslate_mime_type_to_filetype(mime_type, &ftype); if (error) { LOG("xmimemaptranslate_mime_type_to_filetype: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("MiscError", error->errmess); ftype = 0xffd; } } *ftype_out = ftype; return NSERROR_OK; }
/** * Open the login dialog */ void gui_401login_open(nsurl *url, const char *realm, nserror (*cb)(bool proceed, void *pw), void *cbpw) { lwc_string *host = nsurl_get_component(url, NSURL_HOST); assert(host != NULL); ro_gui_401login_open(url, host, realm, cb, cbpw); lwc_string_unref(host); }
extern "C" void gui_401login_open(nsurl *url, const char *realm, nserror (*cb)(bool proceed, void *pw), void *cbpw) { lwc_string *host; host = nsurl_get_component(url, NSURL_HOST); create_login_window(url, host, realm, cb, cbpw); free(host); }
END_TEST /** * check get component asserts on NULL parameter */ START_TEST(nsurl_api_assert_get_component1_test) { lwc_string *lwcs; lwcs = nsurl_get_component(NULL, NSURL_PATH); ck_assert(lwcs == NULL); }
extern "C" nserror gui_401login_open(nsurl *url, const char *realm, const char *username, const char *password, nserror (*cb)(const char *username, const char *password, void *pw), void *cbpw) { lwc_string *host; host = nsurl_get_component(url, NSURL_HOST); create_login_window(url, host, realm, cb, cbpw); free(host); return NSERROR_OK; }
/** callback to set up a resource fetch context. */ static void * fetch_resource_setup(struct fetch *fetchh, nsurl *url, bool only_2xx, bool downgrade_tls, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers) { struct fetch_resource_context *ctx; lwc_string *path; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) return NULL; ctx->handler = fetch_resource_notfound_handler; if ((path = nsurl_get_component(url, NSURL_PATH)) != NULL) { uint32_t i; bool match; /* Ensure requested path is valid */ for (i = 0; i < fetch_resource_path_count; i++) { if (lwc_string_isequal(path, fetch_resource_map[i].path, &match) == lwc_error_ok && match) { ctx->redirect_url = nsurl_ref(fetch_resource_map[i].url); ctx->handler = fetch_resource_redirect_handler; break; } } lwc_string_unref(path); } ctx->url = nsurl_ref(url); ctx->fetchh = fetchh; RING_INSERT(ring, ctx); return ctx; }
/* exported interface documented in content/fetch.h */ bool fetch_can_fetch(const nsurl *url) { scheme_fetcher *fetcher = fetchers; bool match; lwc_string *scheme = nsurl_get_component(url, NSURL_SCHEME); while (fetcher != NULL) { if (lwc_string_isequal(fetcher->scheme_name, scheme, &match) == lwc_error_ok && match == true) { break; } fetcher = fetcher->next_fetcher; } lwc_string_unref(scheme); return fetcher == NULL ? false : fetcher->can_fetch(url); }
END_TEST /** * check get component asserts on bad component parameter */ START_TEST(nsurl_api_assert_get_component2_test) { nserror err; nsurl *res; lwc_string *lwcs; err = nsurl_create(base_str, &res); ck_assert(err == NSERROR_OK); lwcs = nsurl_get_component(res, -1); ck_assert(lwcs == NULL); nsurl_unref(res); }
END_TEST /** * refragment url */ START_TEST(nsurl_refragment_test) { nserror err; nsurl *url; nsurl *res_url; const struct test_pairs *tst = &fragment_tests[_i]; lwc_string *frag; /* not testing create, this should always succeed */ err = nsurl_create(tst->test, &url); ck_assert(err == NSERROR_OK); /* grab the fragment - not testing should succeed */ frag = nsurl_get_component(url, NSURL_FRAGMENT); ck_assert(frag != NULL); nsurl_unref(url); /* not testing create, this should always succeed */ err = nsurl_create(tst->res, &url); ck_assert(err == NSERROR_OK); err = nsurl_refragment(url, frag, &res_url); if (tst->res == NULL) { /* result must be invalid (bad input) */ ck_assert(err != NSERROR_OK); } else { /* result must be valid */ ck_assert(err == NSERROR_OK); ck_assert_str_eq(nsurl_access(res_url), tst->test); nsurl_unref(res_url); } lwc_string_unref(frag); nsurl_unref(url); }
/** callback to set up a about fetch context. */ static void * fetch_about_setup(struct fetch *fetchh, nsurl *url, bool only_2xx, bool downgrade_tls, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers) { struct fetch_about_context *ctx; unsigned int handler_loop; lwc_string *path; bool match; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) return NULL; path = nsurl_get_component(url, NSURL_PATH); for (handler_loop = 0; handler_loop < about_handler_list_len; handler_loop++) { ctx->handler = about_handler_list[handler_loop].handler; if (lwc_string_isequal(path, about_handler_list[handler_loop].lname, &match) == lwc_error_ok && match) { break; } } if (path != NULL) lwc_string_unref(path); ctx->fetchh = fetchh; ctx->url = nsurl_ref(url); RING_INSERT(ring, ctx); return ctx; }
/* exported interface documented in content/fetch.h */ struct fetch * fetch_start(nsurl *url, nsurl *referer, fetch_callback callback, void *p, bool only_2xx, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, bool verifiable, bool downgrade_tls, const char *headers[]) { struct fetch *fetch; scheme_fetcher *fetcher = fetchers; lwc_string *scheme; bool match; fetch = malloc(sizeof (*fetch)); if (fetch == NULL) return NULL; /* The URL we're fetching must have a scheme */ scheme = nsurl_get_component(url, NSURL_SCHEME); assert(scheme != NULL); #ifdef DEBUG_FETCH_VERBOSE LOG(("fetch %p, url '%s'", fetch, nsurl_access(url))); #endif /* construct a new fetch structure */ fetch->callback = callback; fetch->url = nsurl_ref(url); fetch->verifiable = verifiable; fetch->p = p; fetch->http_code = 0; fetch->r_prev = NULL; fetch->r_next = NULL; fetch->referer = NULL; fetch->send_referer = false; fetch->fetcher_handle = NULL; fetch->ops = NULL; fetch->fetch_is_active = false; fetch->host = nsurl_get_component(url, NSURL_HOST); if (referer != NULL) { lwc_string *ref_scheme; fetch->referer = nsurl_ref(referer); ref_scheme = nsurl_get_component(referer, NSURL_SCHEME); /* Not a problem if referer has no scheme */ /* Determine whether to send the Referer header */ if (nsoption_bool(send_referer) && ref_scheme != NULL) { /* User permits us to send the header * Only send it if: * 1) The fetch and referer schemes match * or 2) The fetch is https and the referer is http * * This ensures that referer information is only sent * across schemes in the special case of an https * request from a page served over http. The inverse * (https -> http) should not send the referer (15.1.3) */ bool match1; bool match2; if (lwc_string_isequal(scheme, ref_scheme, &match) != lwc_error_ok) { match = false; } if (lwc_string_isequal(scheme, corestring_lwc_https, &match1) != lwc_error_ok) { match1 = false; } if (lwc_string_isequal(ref_scheme, corestring_lwc_http, &match2) != lwc_error_ok) { match2= false; } if (match == true || (match1 == true && match2 == true)) fetch->send_referer = true; } if (ref_scheme != NULL) lwc_string_unref(ref_scheme); } /* Pick the scheme ops */ while (fetcher) { if ((lwc_string_isequal(fetcher->scheme_name, scheme, &match) == lwc_error_ok) && (match == true)) { fetch->ops = fetcher; break; } fetcher = fetcher->next_fetcher; } if (fetch->ops == NULL) goto failed; /* Got a scheme fetcher, try and set up the fetch */ fetch->fetcher_handle = fetch->ops->setup_fetch(fetch, url, only_2xx, downgrade_tls, post_urlenc, post_multipart, headers); if (fetch->fetcher_handle == NULL) goto failed; /* Rah, got it, so ref the fetcher. */ fetch_ref_fetcher(fetch->ops); /* these aren't needed past here */ lwc_string_unref(scheme); /* Dump us in the queue and ask the queue to run. */ RING_INSERT(queue_ring, fetch); fetch_dispatch_jobs(); return fetch; failed: lwc_string_unref(scheme); if (fetch->host != NULL) lwc_string_unref(fetch->host); if (fetch->url != NULL) nsurl_unref(fetch->url); if (fetch->referer != NULL) nsurl_unref(fetch->referer); free(fetch); return NULL; }
/* exported interface documented in image_cache.h */ int image_cache_snentryf(char *string, size_t size, unsigned int entryn, const char *fmt) { struct image_cache_entry_s *centry; size_t slen = 0; /* current output string length */ int fmtc = 0; /* current index into format string */ lwc_string *origin; /* current entry's origin */ centry = image_cache__findn(entryn); if (centry == NULL) return -1; while((slen < size) && (fmt[fmtc] != 0)) { if (fmt[fmtc] == '%') { fmtc++; switch (fmt[fmtc]) { case 'e': slen += snprintf(string + slen, size - slen, "%d", entryn); break; case 'r': slen += snprintf(string + slen, size - slen, "%u", centry->redraw_count); break; case 'a': slen += snprintf(string + slen, size - slen, "%.2f", (float)((image_cache->current_age - centry->redraw_age)) / 1000); break; case 'c': slen += snprintf(string + slen, size - slen, "%d", centry->conversion_count); break; case 'g': slen += snprintf(string + slen, size - slen, "%.2f", (float)((image_cache->current_age - centry->bitmap_age)) / 1000); break; case 'k': slen += snprintf(string + slen, size - slen, "%p", centry->content); break; case 'U': slen += snprintf(string + slen, size - slen, "%s", nsurl_access(llcache_handle_get_url(centry->content->llcache))); break; case 'o': if (nsurl_has_component(llcache_handle_get_url( centry->content->llcache), NSURL_HOST)) { origin = nsurl_get_component( llcache_handle_get_url( centry->content-> llcache), NSURL_HOST); slen += snprintf(string + slen, size - slen, "%s", lwc_string_data( origin)); lwc_string_unref(origin); } else { slen += snprintf(string + slen, size - slen, "%s", "localhost"); } break; case 's': if (centry->bitmap != NULL) { slen += snprintf(string + slen, size - slen, "%"SSIZET_FMT, centry->bitmap_size); } else { slen += snprintf(string + slen, size - slen, "0"); } break; } fmtc++; } else { string[slen] = fmt[fmtc]; slen++; fmtc++; } } /* Ensure that we NUL-terminate the output */ string[min(slen, size - 1)] = '\0'; return slen; }
static struct gui_download_window * gui_download_window_create(download_context *ctx, struct gui_window *gui) { nsurl *url = download_context_get_url(ctx); unsigned long total_size = download_context_get_total_length(ctx); gchar *domain; gchar *destination; gboolean unknown_size = total_size == 0; const char *size = (total_size == 0 ? messages_get("gtkUnknownSize") : human_friendly_bytesize(total_size)); nsgtk_download_parent = nsgtk_scaffolding_window(nsgtk_get_scaffold(gui)); struct gui_download_window *download = malloc(sizeof *download); if (download == NULL) { return NULL; } /* set the domain to the host component of the url if it exists */ if (nsurl_has_component(url, NSURL_HOST)) { domain = g_strdup(lwc_string_data(nsurl_get_component(url, NSURL_HOST))); } else { domain = g_strdup(messages_get("gtkUnknownHost")); } if (domain == NULL) { free(download); return NULL; } /* show the dialog */ destination = nsgtk_download_dialog_show( download_context_get_filename(ctx), domain, size); if (destination == NULL) { g_free(domain); free(download); return NULL; } /* Add the new row and store the reference to it (which keeps track of * the tree changes) */ gtk_list_store_prepend(nsgtk_download_store, &nsgtk_download_iter); download->row = gtk_tree_row_reference_new( GTK_TREE_MODEL(nsgtk_download_store), gtk_tree_model_get_path( GTK_TREE_MODEL(nsgtk_download_store), &nsgtk_download_iter)); download->ctx = ctx; download->name = g_string_new(download_context_get_filename(ctx)); download->time_left = g_string_new(""); download->size_total = total_size; download->size_downloaded = 0; download->speed = 0; download->start_time = g_timer_elapsed(nsgtk_downloads_timer, NULL); download->time_remaining = -1; download->status = NSGTK_DOWNLOAD_NONE; download->progress = 0; download->error = NULL; download->write = g_io_channel_new_file(destination, "w", &download->error); if (nsgtk_download_handle_error(download->error)) { g_string_free(download->name, TRUE); g_string_free(download->time_left, TRUE); free(download); return NULL; } g_io_channel_set_encoding(download->write, NULL, &download->error); nsgtk_download_change_sensitivity(download, NSGTK_DOWNLOAD_CANCEL); nsgtk_download_store_create_item(download); nsgtk_download_show(nsgtk_download_parent); if (unknown_size) nsgtk_download_change_status(download, NSGTK_DOWNLOAD_WORKING); if (nsgtk_downloads_num_active == 0) { g_timeout_add(UPDATE_RATE, (GSourceFunc) nsgtk_download_update, FALSE); } nsgtk_downloads_list = g_list_prepend(nsgtk_downloads_list, download); return download; }
/** * Start fetching data for the given URL. * * The function returns immediately. The fetch may be queued for later * processing. * * A pointer to an opaque struct curl_fetch_info is returned, which can be * passed to fetch_abort() to abort the fetch at any time. Returns 0 if memory * is exhausted (or some other fatal error occurred). * * The caller must supply a callback function which is called when anything * interesting happens. The callback function is first called with msg * FETCH_HEADER, with the header in data, then one or more times * with FETCH_DATA with some data for the url, and finally with * FETCH_FINISHED. Alternatively, FETCH_ERROR indicates an error occurred: * data contains an error message. FETCH_REDIRECT may replace the FETCH_HEADER, * FETCH_DATA, FETCH_FINISHED sequence if the server sends a replacement URL. * * Some private data can be passed as the last parameter to fetch_start, and * callbacks will contain this. */ static void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url, bool only_2xx, bool downgrade_tls, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers) { struct curl_fetch_info *fetch; struct curl_slist *slist; int i; fetch = malloc(sizeof (*fetch)); if (fetch == NULL) return 0; fetch->fetch_handle = parent_fetch; LOG("fetch %p, url '%s'", fetch, nsurl_access(url)); /* construct a new fetch structure */ fetch->curl_handle = NULL; fetch->had_headers = false; fetch->abort = false; fetch->stopped = false; fetch->only_2xx = only_2xx; fetch->downgrade_tls = downgrade_tls; fetch->headers = NULL; fetch->url = nsurl_ref(url); fetch->host = nsurl_get_component(url, NSURL_HOST); fetch->location = NULL; fetch->content_length = 0; fetch->http_code = 0; fetch->cookie_string = NULL; fetch->realm = NULL; fetch->post_urlenc = NULL; fetch->post_multipart = NULL; if (post_urlenc) { fetch->post_urlenc = strdup(post_urlenc); } else if (post_multipart) { fetch->post_multipart = fetch_curl_post_convert(post_multipart); } fetch->last_progress_update = 0; /* TLS defaults */ memset(fetch->cert_data, 0, sizeof(fetch->cert_data)); fetch->cert_depth = -1; if ((fetch->host == NULL) || (post_multipart != NULL && fetch->post_multipart == NULL) || (post_urlenc != NULL && fetch->post_urlenc == NULL)) { goto failed; } #define APPEND(list, value) \ slist = curl_slist_append(list, value); \ if (slist == NULL) \ goto failed; \ list = slist; /* remove curl default headers */ APPEND(fetch->headers, "Pragma:"); /* when doing a POST libcurl sends Expect: 100-continue" by default * which fails with lighttpd, so disable it (see bug 1429054) */ APPEND(fetch->headers, "Expect:"); if ((nsoption_charp(accept_language) != NULL) && (nsoption_charp(accept_language)[0] != '\0')) { char s[80]; snprintf(s, sizeof s, "Accept-Language: %s, *;q=0.1", nsoption_charp(accept_language)); s[sizeof s - 1] = 0; APPEND(fetch->headers, s); } if (nsoption_charp(accept_charset) != NULL && nsoption_charp(accept_charset)[0] != '\0') { char s[80]; snprintf(s, sizeof s, "Accept-Charset: %s, *;q=0.1", nsoption_charp(accept_charset)); s[sizeof s - 1] = 0; APPEND(fetch->headers, s); } if (nsoption_bool(do_not_track) == true) { APPEND(fetch->headers, "DNT: 1"); } /* And add any headers specified by the caller */ for (i = 0; headers[i] != NULL; i++) { APPEND(fetch->headers, headers[i]); } return fetch; #undef APPEND failed: if (fetch->host != NULL) lwc_string_unref(fetch->host); nsurl_unref(fetch->url); free(fetch->post_urlenc); if (fetch->post_multipart) curl_formfree(fetch->post_multipart); curl_slist_free_all(fetch->headers); free(fetch); return NULL; }