| /* |
| * 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"); |
| } |