/** * Process fetch headers for a download context. * Extracts MIME type, total length, and creates gui_download_window * * \param ctx Context to process * \return NSERROR_OK on success, appropriate error otherwise */ static nserror download_context_process_headers(download_context *ctx) { const char *http_header; char *mime_type; http_parameter *params; unsigned long length; nserror error; /* Retrieve and parse Content-Type */ http_header = llcache_handle_get_header(ctx->llcache, "Content-Type"); if (http_header == NULL) http_header = "text/plain"; error = http_parse_content_type(http_header, &mime_type, ¶ms); if (error != NSERROR_OK) return error; /* Don't care about parameters */ http_parameter_list_destroy(params); /* Retrieve and parse Content-Length */ http_header = llcache_handle_get_header(ctx->llcache, "Content-Length"); if (http_header == NULL) length = 0; else length = strtoul(http_header, NULL, 10); ctx->mime_type = mime_type; ctx->total_length = length; /* Create the frontend window */ ctx->window = gui_download_window_create(ctx, ctx->parent); if (ctx->window == NULL) { free(ctx->mime_type); ctx->mime_type = NULL; return NSERROR_NOMEM; } return NSERROR_OK; }
/** * Create a content object * * \param llcache Underlying source data handle * \param fallback_charset Character set to fall back to if none specified * \param quirks Quirkiness of containing document * \param effective_type Effective MIME type of content * \return Pointer to content object, or NULL on failure */ struct content *content_factory_create_content(llcache_handle *llcache, const char *fallback_charset, bool quirks, lwc_string *effective_type) { struct content *c; const char *content_type_header; const content_handler *handler; http_content_type *ct = NULL; nserror error; handler = content_lookup(effective_type); if (handler == NULL) return NULL; assert(handler->create != NULL); /* Use the parameters from the declared Content-Type header */ content_type_header = llcache_handle_get_header(llcache, "Content-Type"); if (content_type_header != NULL) { /* We don't care if this fails */ http_parse_content_type(content_type_header, &ct); } error = handler->create(handler, effective_type, ct != NULL ? ct->parameters : NULL, llcache, fallback_charset, quirks, &c); if (ct != NULL) http_content_type_destroy(ct); if (error != NSERROR_OK) return NULL; return c; }
/* See mimesniff.h for documentation */ nserror mimesniff_compute_effective_type(llcache_handle *handle, const uint8_t *data, size_t len, bool sniff_allowed, bool image_only, lwc_string **effective_type) { #define S(s) { s, SLEN(s) } static const struct tt_s { const char *data; size_t len; } text_types[] = { S("text/plain"), S("text/plain; charset=ISO-8859-1"), S("text/plain; charset=iso-8859-1"), S("text/plain; charset=UTF-8"), { NULL, 0 } }; #undef S const char *content_type_header; size_t content_type_header_len; http_content_type *ct; const struct tt_s *tt; bool match; nserror error; content_type_header = llcache_handle_get_header(handle, "Content-Type"); if (content_type_header == NULL) { if (sniff_allowed == false) return NSERROR_NOT_FOUND; /* No official type => unknown */ return mimesniff__compute_unknown(data, len, effective_type); } error = http_parse_content_type(content_type_header, &ct); if (error != NSERROR_OK) { if (sniff_allowed == false) return NSERROR_NOT_FOUND; /* Unparseable => unknown */ return mimesniff__compute_unknown(data, len, effective_type); } if (sniff_allowed == false) { *effective_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return NSERROR_OK; } if (image_only) { lwc_string *official_type; if (lwc_string_caseless_isequal(ct->media_type, image_svg, &match) == lwc_error_ok && match) { *effective_type = lwc_string_ref(image_svg); http_content_type_destroy(ct); return NSERROR_OK; } official_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return mimesniff__compute_image(official_type, data, len, effective_type); } content_type_header_len = strlen(content_type_header); /* Look for text types */ for (tt = text_types; tt->data != NULL; tt++) { if (tt->len == content_type_header_len && memcmp(tt->data, content_type_header, content_type_header_len) == 0) { http_content_type_destroy(ct); return mimesniff__compute_text_or_binary(data, len, effective_type); } } /* unknown/unknown, application/unknown, * / * */ if ((lwc_string_caseless_isequal(ct->media_type, unknown_unknown, &match) == lwc_error_ok && match) || (lwc_string_caseless_isequal(ct->media_type, application_unknown, &match) == lwc_error_ok && match) || (lwc_string_caseless_isequal(ct->media_type, any, &match) == lwc_error_ok && match)) { http_content_type_destroy(ct); return mimesniff__compute_unknown(data, len, effective_type); } /* +xml */ if (lwc_string_length(ct->media_type) > SLEN("+xml") && strncasecmp(lwc_string_data(ct->media_type) + lwc_string_length(ct->media_type) - SLEN("+xml"), "+xml", SLEN("+xml")) == 0) { /* Use official type */ *effective_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return NSERROR_OK; } /* text/xml, application/xml */ if ((lwc_string_caseless_isequal(ct->media_type, text_xml, &match) == lwc_error_ok && match) || (lwc_string_caseless_isequal(ct->media_type, application_xml, &match) == lwc_error_ok && match)) { /* Use official type */ *effective_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return NSERROR_OK; } /* Image types */ if (content_factory_type_from_mime_type(ct->media_type) == CONTENT_IMAGE) { lwc_string *official_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return mimesniff__compute_image(official_type, data, len, effective_type); } /* text/html */ if ((lwc_string_caseless_isequal(ct->media_type, text_html, &match) == lwc_error_ok && match)) { http_content_type_destroy(ct); return mimesniff__compute_feed_or_html(data, len, effective_type); } /* Use official type */ *effective_type = lwc_string_ref(ct->media_type); http_content_type_destroy(ct); return NSERROR_OK; }
/** * Process fetch headers for a download context. * Extracts MIME type, total length, and creates gui_download_window * * \param ctx Context to process * \return NSERROR_OK on success, appropriate error otherwise */ static nserror download_context_process_headers(download_context *ctx) { const char *http_header; http_content_type *content_type; unsigned long length; nserror error; /* Retrieve and parse Content-Type */ http_header = llcache_handle_get_header(ctx->llcache, "Content-Type"); if (http_header == NULL) http_header = "text/plain"; error = http_parse_content_type(http_header, &content_type); if (error != NSERROR_OK) return error; /* Retrieve and parse Content-Length */ http_header = llcache_handle_get_header(ctx->llcache, "Content-Length"); if (http_header == NULL) length = 0; else length = strtoul(http_header, NULL, 10); /* Retrieve and parse Content-Disposition */ http_header = llcache_handle_get_header(ctx->llcache, "Content-Disposition"); if (http_header != NULL) { lwc_string *filename_value; http_content_disposition *disposition; error = http_parse_content_disposition(http_header, &disposition); if (error != NSERROR_OK) { http_content_type_destroy(content_type); return error; } error = http_parameter_list_find_item(disposition->parameters, corestring_lwc_filename, &filename_value); if (error == NSERROR_OK) { ctx->filename = download_parse_filename( lwc_string_data(filename_value)); lwc_string_unref(filename_value); } http_content_disposition_destroy(disposition); } ctx->mime_type = lwc_string_ref(content_type->media_type); ctx->total_length = length; if (ctx->filename == NULL) { ctx->filename = download_default_filename( llcache_handle_get_url(ctx->llcache)); } http_content_type_destroy(content_type); if (ctx->filename == NULL) { lwc_string_unref(ctx->mime_type); ctx->mime_type = NULL; return NSERROR_NOMEM; } /* Create the frontend window */ ctx->window = guit->download->create(ctx, ctx->parent); if (ctx->window == NULL) { free(ctx->filename); ctx->filename = NULL; lwc_string_unref(ctx->mime_type); ctx->mime_type = NULL; return NSERROR_NOMEM; } return NSERROR_OK; }