/** * Initialise a CSS content * * \param c Content to initialise * \param params Content-Type parameters * \return true on success, false on failure */ nserror nscss_create(const content_handler *handler, lwc_string *imime_type, const http_parameter *params, llcache_handle *llcache, const char *fallback_charset, bool quirks, struct content **c) { nscss_content *result; const char *charset = NULL; const char *xnsbase = NULL; lwc_string *charset_value = NULL; union content_msg_data msg_data; nserror error; result = calloc(1, sizeof(nscss_content)); if (result == NULL) return NSERROR_NOMEM; error = content__init(&result->base, handler, imime_type, params, llcache, fallback_charset, quirks); if (error != NSERROR_OK) { free(result); return error; } /* Find charset specified on HTTP layer, if any */ error = http_parameter_list_find_item(params, css_charset, &charset_value); if (error != NSERROR_OK || lwc_string_length(charset_value) == 0) { /* No charset specified, use fallback, if any */ /** \todo libcss will take this as gospel, which is wrong */ charset = fallback_charset; } else { charset = lwc_string_data(charset_value); } /* Compute base URL for stylesheet */ xnsbase = llcache_handle_get_header(llcache, "X-NS-Base"); if (xnsbase == NULL) { xnsbase = nsurl_access(content_get_url(&result->base)); } error = nscss_create_css_data(&result->data, xnsbase, charset, result->base.quirks, nscss_content_done, result); if (error != NSERROR_OK) { msg_data.error = messages_get("NoMemory"); content_broadcast(&result->base, CONTENT_MSG_ERROR, msg_data); if (charset_value != NULL) lwc_string_unref(charset_value); free(result); return error; } if (charset_value != NULL) lwc_string_unref(charset_value); *c = (struct content *) result; 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; 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; }