1/*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *  * Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 *  * Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebResponse.h"
28
29#include "MIMETypeRegistry.h"
30#include "PlatformString.h"
31#include "ResourceResponse.h"
32#include "ResourceError.h"
33
34#include <wtf/text/CString.h>
35
36using namespace std;
37
38namespace android {
39
40WebResponse::WebResponse(net::URLRequest* request)
41    : m_httpStatusCode(0)
42{
43    // The misleadingly-named os_error() is actually a net::Error enum constant.
44    m_error = net::Error(request->status().os_error());
45
46    m_url = request->url().spec();
47    m_host = request->url().HostNoBrackets();
48    request->GetMimeType(&m_mime);
49
50    request->GetCharset(&m_encoding);
51    m_expectedSize = request->GetExpectedContentSize();
52
53    m_sslInfo = request->ssl_info();
54
55    net::HttpResponseHeaders* responseHeaders = request->response_headers();
56    if (!responseHeaders)
57        return;
58
59    m_httpStatusCode = responseHeaders->response_code();
60    m_httpStatusText = responseHeaders->GetStatusText();
61
62    string value;
63    string name;
64    void* iter = 0;
65    while (responseHeaders->EnumerateHeaderLines(&iter, &name, &value))
66        m_headerFields[name] = value;
67}
68
69WebResponse::WebResponse(const string &url, const string &mimeType, long long expectedSize, const string &encoding, int httpStatusCode)
70    : m_error(net::OK)
71    , m_encoding(encoding)
72    , m_httpStatusCode(httpStatusCode)
73    , m_expectedSize(expectedSize)
74    , m_mime(mimeType)
75    , m_url(url)
76{
77}
78
79WebCore::ResourceResponse WebResponse::createResourceResponse()
80{
81    WebCore::ResourceResponse resourceResponse(createKurl(), getMimeType().c_str(), m_expectedSize, m_encoding.c_str(), "");
82    resourceResponse.setHTTPStatusCode(m_httpStatusCode);
83    resourceResponse.setHTTPStatusText(m_httpStatusText.c_str());
84
85    map<string, string>::const_iterator it;
86    for (it = m_headerFields.begin(); it != m_headerFields.end(); ++it)
87        resourceResponse.setHTTPHeaderField(it->first.c_str(), it->second.c_str());
88
89    return resourceResponse;
90}
91
92WebCore::ResourceError WebResponse::createResourceError()
93{
94    WebCore::ResourceError error(m_host.c_str(), ToWebViewClientError(m_error), m_url.c_str(), WTF::String());
95    return error;
96}
97
98
99WebCore::KURL WebResponse::createKurl()
100{
101    WebCore::KURL kurl(WebCore::ParsedURLString, m_url.c_str());
102    return kurl;
103}
104
105const string& WebResponse::getUrl() const
106{
107    return m_url;
108}
109
110void WebResponse::setUrl(const string& url)
111{
112    m_url = url;
113}
114
115// Calls WebCore APIs so should only be called from the WebCore thread.
116// TODO: can we return a WTF::String directly? Need to check all callsites.
117const string& WebResponse::getMimeType()
118{
119    if (!m_url.length())
120        return m_mime;
121
122    if (!m_mime.length() || !m_mime.compare("text/plain") || !m_mime.compare("application/octet-stream"))
123        m_mime = resolveMimeType(m_url, m_mime);
124
125    return m_mime;
126}
127
128const string WebResponse::resolveMimeType(const string& url, const string& old_mime)
129{
130    // Use "text/html" as a default (matching the behaviour of the Apache
131    // HTTP stack -- see guessMimeType() in LoadListener.java).
132    string mimeType = old_mime.length() ? old_mime : "text/html";
133    // Try to guess a better MIME type from the URL. We call
134    // getMIMETypeForExtension rather than getMIMETypeForPath because the
135    // latter defaults to "application/octet-stream" on failure.
136    WebCore::KURL kurl(WebCore::ParsedURLString, url.c_str());
137    WTF::String path = kurl.path();
138    size_t extensionPos = path.reverseFind('.');
139    if (extensionPos != WTF::notFound) {
140        // We found a file extension.
141        path.remove(0, extensionPos + 1);
142        // TODO: Should use content-disposition instead of url if it is there
143        WTF::String mime = WebCore::MIMETypeRegistry::getMIMETypeForExtension(path);
144        if (!mime.isEmpty()) {
145            // Great, we found a MIME type.
146            mimeType = std::string(mime.utf8().data(), mime.length());
147        }
148    }
149    return mimeType;
150}
151
152bool WebResponse::getHeader(const string& header, string* result) const
153{
154    map<string, string>::const_iterator iter = m_headerFields.find(header);
155    if (iter == m_headerFields.end())
156        return false;
157    if (result)
158        *result = iter->second;
159    return true;
160}
161
162long long WebResponse::getExpectedSize() const
163{
164    return m_expectedSize;
165}
166
167} // namespace android
168