1/*
2 * Copyright (C) 2011 Apple Inc. All Rights Reserved.
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 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. 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 APPLE INC. ``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 APPLE INC. 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 "HTTPRequest.h"
28
29#include <wtf/text/CString.h>
30
31using namespace WebCore;
32
33namespace WebKit {
34
35PassRefPtr<HTTPRequest> HTTPRequest::parseHTTPRequestFromBuffer(const char* data, size_t length, String& failureReason)
36{
37    if (!length) {
38        failureReason = "No data to parse.";
39        return 0;
40    }
41
42    // Request we will be building.
43    RefPtr<HTTPRequest> request = HTTPRequest::create();
44
45    // Advance a pointer through the data as needed.
46    const char* pos = data;
47    size_t remainingLength = length;
48
49    // 1. Parse Method + URL.
50    size_t requestLineLength = request->parseRequestLine(pos, remainingLength, failureReason);
51    if (!requestLineLength)
52        return 0;
53    pos += requestLineLength;
54    remainingLength -= requestLineLength;
55
56    // 2. Parse HTTP Headers.
57    size_t headersLength = request->parseHeaders(pos, remainingLength, failureReason);
58    if (!headersLength)
59        return 0;
60    pos += headersLength;
61    remainingLength -= headersLength;
62
63    // 3. Parse HTTP Data.
64    size_t dataLength = request->parseRequestBody(pos, remainingLength);
65    pos += dataLength;
66    remainingLength -= dataLength;
67
68    // We should have processed the entire input.
69    ASSERT(!remainingLength);
70    return request.release();
71}
72
73size_t HTTPRequest::parseRequestLine(const char* data, size_t length, String& failureReason)
74{
75    String url;
76    size_t result = parseHTTPRequestLine(data, length, failureReason, m_requestMethod, url, m_httpVersion);
77    m_url = URL(URL(), url);
78    return result;
79}
80
81size_t HTTPRequest::parseHeaders(const char* data, size_t length, String& failureReason)
82{
83    const char* p = data;
84    const char* end = data + length;
85    String name;
86    String value;
87    for (; p < data + length; p++) {
88        size_t consumedLength = parseHTTPHeader(p, end - p, failureReason, name, value);
89        if (!consumedLength)
90            return 0;
91        p += consumedLength;
92        if (name.isEmpty())
93            break;
94        m_headerFields.add(name, value);
95    }
96
97    // If we got here and "name" is empty, it means the headers are valid and ended with a
98    // blank line (parseHTTPHeader returns "name" as empty if parsing a blank line), otherwise
99    // the headers didn't end with a blank line and we have an invalid request.
100    // See also http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
101    if (!name.isEmpty())
102        return 0;
103    return p - data;
104}
105
106size_t HTTPRequest::parseRequestBody(const char* data, size_t length)
107{
108    return parseHTTPRequestBody(data, length, m_body);
109}
110
111HTTPRequest::HTTPRequest()
112    : m_httpVersion(WebCore::Unknown)
113{
114}
115
116HTTPRequest::HTTPRequest(const String& requestMethod, const URL& url, HTTPVersion version)
117    : m_url(url)
118    , m_httpVersion(version)
119    , m_requestMethod(requestMethod)
120{
121}
122
123HTTPRequest::~HTTPRequest()
124{
125}
126
127} // namespace WebCore
128