/* * Copyright 2009, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define LOG_TAG "webcore_test" #include "config.h" #include "Base64.h" #include "CString.h" #include "HashMap.h" #include "HTTPParsers.h" #include "Intercept.h" #include "ResourceHandle.h" #include "ResourceHandleClient.h" #include "ResourceRequest.h" #include "ResourceResponse.h" #include "StringHash.h" #include "TextEncoding.h" #include <utils/Log.h> void MyResourceLoader::handleRequest() { if (protocolIs(m_url, "data")) loadData(m_url.substring(5)); // 5 for data: else if (protocolIs(m_url, "file")) loadFile(m_url.substring(7)); // 7 for file:// } void MyResourceLoader::loadData(const String& data) { LOGD("Loading data (%s) ...", data.latin1().data()); ResourceHandleClient* client = m_handle->client(); int index = data.find(','); if (index == -1) { client->cannotShowURL(m_handle); return; } String mediaType = data.substring(0, index); String base64 = data.substring(index + 1); bool decode = mediaType.endsWith(";base64", false); if (decode) mediaType = mediaType.left(mediaType.length() - 7); // 7 for base64; if (mediaType.isEmpty()) mediaType = "text/plain;charset=US-ASCII"; String mimeType = extractMIMETypeFromMediaType(mediaType); String charset = extractCharsetFromMediaType(mediaType); ResourceResponse response; response.setMimeType(mimeType); if (decode) { base64 = decodeURLEscapeSequences(base64); response.setTextEncodingName(charset); client->didReceiveResponse(m_handle, response); // FIXME: This is annoying. WebCore's Base64 decoder chokes on spaces. // That is correct with strict decoding but html authors (particularly // the acid3 authors) put spaces in the data which should be ignored. // Remove them here before sending to the decoder. Vector<char> in; CString str = base64.latin1(); const char* chars = str.data(); unsigned i = 0; while (i < str.length()) { char c = chars[i]; // Don't send spaces or control characters. if (c != ' ' && c != '\n' && c != '\t' && c != '\b' && c != '\f' && c != '\r') in.append(chars[i]); i++; } Vector<char> out; if (base64Decode(in, out) && out.size() > 0) client->didReceiveData(m_handle, out.data(), out.size(), 0); } else { base64 = decodeURLEscapeSequences(base64, TextEncoding(charset)); response.setTextEncodingName("UTF-16"); client->didReceiveResponse(m_handle, response); if (base64.length() > 0) client->didReceiveData(m_handle, (const char*)base64.characters(), base64.length() * sizeof(UChar), 0); } client->didFinishLoading(m_handle); } static String mimeTypeForExtension(const String& file) { static HashMap<String, String, CaseFoldingHash> extensionToMime; if (extensionToMime.isEmpty()) { extensionToMime.set("txt", "text/plain"); extensionToMime.set("html", "text/html"); extensionToMime.set("htm", "text/html"); extensionToMime.set("png", "image/png"); extensionToMime.set("jpeg", "image/jpeg"); extensionToMime.set("jpg", "image/jpeg"); extensionToMime.set("gif", "image/gif"); extensionToMime.set("ico", "image/x-icon"); extensionToMime.set("js", "text/javascript"); } int dot = file.reverseFind('.'); String mime("text/plain"); if (dot != -1) { String ext = file.substring(dot + 1); if (extensionToMime.contains(ext)) mime = extensionToMime.get(ext); } return mime; } void MyResourceLoader::loadFile(const String& file) { LOGD("Loading file (%s) ...", file.latin1().data()); FILE* f = fopen(file.latin1().data(), "r"); ResourceHandleClient* client = m_handle->client(); if (!f) { client->didFail(m_handle, ResourceError("", -14, file, "Could not open file")); } else { ResourceResponse response; response.setTextEncodingName("utf-8"); response.setMimeType(mimeTypeForExtension(file)); client->didReceiveResponse(m_handle, response); char buf[512]; while (true) { int res = fread(buf, 1, sizeof(buf), f); if (res <= 0) break; client->didReceiveData(m_handle, buf, res, 0); } fclose(f); client->didFinishLoading(m_handle); } } WebCoreResourceLoader* MyWebFrame::startLoadingResource(ResourceHandle* handle, const ResourceRequest& req, bool ignore1, bool ignore2) { MyResourceLoader* loader = new MyResourceLoader(handle, req.url().string()); Retain(loader); m_requests.append(loader); if (!m_timer.isActive()) m_timer.startOneShot(0); return loader; } void MyWebFrame::timerFired(Timer<MyWebFrame>*) { LOGD("Handling requests..."); Vector<MyResourceLoader*> reqs; reqs.swap(m_requests); Vector<MyResourceLoader*>::iterator i = reqs.begin(); Vector<MyResourceLoader*>::iterator end = reqs.end(); for (; i != end; i++) { (*i)->handleRequest(); Release(*i); } LOGD("...done"); }