https://bugs.webkit.org/show_bug.cgi?id=73092
Reviewed by Simon Hausmann.
A WebSocket server will need to read HTTP Requests before upgrading
to WebSocket framing. This patch creates a cross-platform HTTPRequest
class. Since some of this was already done in WebSocket code:
- the header parsing code was extracted and put into HTTPParsers.cpp
- WebSocketHandshakeRequest subclasses HTTPRequest
- WebSocket code was refactored for these changes
Refactoring is covered by existing http/tests/websocket tests.
* CMakeLists.txt:
* GNUmakefile.list.am:
* Modules/websockets/WebSocketChannel.cpp:
(WebCore::WebSocketChannel::didOpenSocketStream):
Extract the HTTP Header parsing out of WebSocketHandshake and
put it into HTTP Parsers. Now make use of the generic parsing.
* Modules/websockets/WebSocketHandshake.cpp:
(WebCore):
(WebCore::trimInputSample):
(WebCore::WebSocketHandshake::clientHandshakeRequest): switch to RefCounted HandshakeRequest.
(WebCore::WebSocketHandshake::readStatusLine):
(WebCore::WebSocketHandshake::readHTTPHeaders): use generic HTTPParsers parsing.
* Modules/websockets/WebSocketHandshake.h: switch to RefCounted HandshakeRequest.
WebSocketHandshakeRequest is a specialization of an HTTPRequest.
Much of its original code was abstracted into HTTPRequest, and
this is now a subclass with WebSocket key information.
* Modules/websockets/WebSocketHandshakeRequest.cpp:
(WebCore::WebSocketHandshakeRequest::WebSocketHandshakeRequest): initialize now calls super.
* Modules/websockets/WebSocketHandshakeRequest.h:
(WebCore::WebSocketHandshakeRequest::create): switch to being ref counted like HTTPRequest.
(WebSocketHandshakeRequest):
* Target.pri:
* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
Add generic HTTP Request parsing functions to HTTPParsers.cpp.
Use out parameters to get values after parsing.
* platform/network/HTTPParsers.cpp:
(WebCore):
(WebCore::trimInputSample): taken from WebSocket parsing.
(WebCore::parseHTTPRequestLine): new code, parse a request line.
(WebCore::parseHTTPHeaders): taken from previous WebSocket parsing. Algorithm unchanged.
(WebCore::parseHTTPRequestBody): new code, just copy the date into the provided buffer.
* platform/network/HTTPParsers.h:
(WebCore):
This adds a general HTTPRequest class. Accessors for the
request method, url, httpVersion, headers, and data. You can
create an HTTPRequest using the constructor, or parse one
from a data buffer, such as one read from a socket.
* platform/network/HTTPRequest.cpp: Added.
(WebCore):
(WebCore::HTTPRequest::parseHTTPRequestFromBuffer): create an HTTPRequest by parsing data in a buffer.
(WebCore::HTTPRequest::parseRequestLine): helper to initialize members while parsing.
(WebCore::HTTPRequest::parseHeaders): helper to initialize members while parsing.
(WebCore::HTTPRequest::parseRequestBody): helper to initialize members while parsing.
(WebCore::HTTPRequest::HTTPRequest):
(WebCore::HTTPRequest::~HTTPRequest):
* platform/network/HTTPRequest.h: Added.
(WebCore):
(HTTPRequest):
(WebCore::HTTPRequest::create): create an empty request, or specify details.
(WebCore::HTTPRequest::requestMethod):
(WebCore::HTTPRequest::setRequestMethod):
(WebCore::HTTPRequest::url):
(WebCore::HTTPRequest::setURL):
(WebCore::HTTPRequest::body):
(WebCore::HTTPRequest::headerFields):
(WebCore::HTTPRequest::addHeaderField):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@113024
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
platform/network/FormData.cpp
platform/network/HTTPHeaderMap.cpp
platform/network/HTTPParsers.cpp
+ platform/network/HTTPRequest.cpp
platform/network/HTTPValidation.cpp
platform/network/MIMEHeader.cpp
platform/network/NetworkStateNotifier.cpp
+2012-03-29 Joseph Pecoraro <joepeck@webkit.org> and Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Add Generic HTTP Request Class. Generalized HTTP Parsing.
+ https://bugs.webkit.org/show_bug.cgi?id=73092
+
+ Reviewed by Simon Hausmann.
+
+ A WebSocket server will need to read HTTP Requests before upgrading
+ to WebSocket framing. This patch creates a cross-platform HTTPRequest
+ class. Since some of this was already done in WebSocket code:
+
+ - the header parsing code was extracted and put into HTTPParsers.cpp
+ - WebSocketHandshakeRequest subclasses HTTPRequest
+ - WebSocket code was refactored for these changes
+
+ Refactoring is covered by existing http/tests/websocket tests.
+
+ * CMakeLists.txt:
+ * GNUmakefile.list.am:
+
+ * Modules/websockets/WebSocketChannel.cpp:
+ (WebCore::WebSocketChannel::didOpenSocketStream):
+
+ Extract the HTTP Header parsing out of WebSocketHandshake and
+ put it into HTTP Parsers. Now make use of the generic parsing.
+
+ * Modules/websockets/WebSocketHandshake.cpp:
+ (WebCore):
+ (WebCore::trimInputSample):
+ (WebCore::WebSocketHandshake::clientHandshakeRequest): switch to RefCounted HandshakeRequest.
+ (WebCore::WebSocketHandshake::readStatusLine):
+ (WebCore::WebSocketHandshake::readHTTPHeaders): use generic HTTPParsers parsing.
+ * Modules/websockets/WebSocketHandshake.h: switch to RefCounted HandshakeRequest.
+
+ WebSocketHandshakeRequest is a specialization of an HTTPRequest.
+ Much of its original code was abstracted into HTTPRequest, and
+ this is now a subclass with WebSocket key information.
+
+ * Modules/websockets/WebSocketHandshakeRequest.cpp:
+ (WebCore::WebSocketHandshakeRequest::WebSocketHandshakeRequest): initialize now calls super.
+ * Modules/websockets/WebSocketHandshakeRequest.h:
+ (WebCore::WebSocketHandshakeRequest::create): switch to being ref counted like HTTPRequest.
+ (WebSocketHandshakeRequest):
+
+ * Target.pri:
+ * WebCore.gypi:
+ * WebCore.vcproj/WebCore.vcproj:
+ * WebCore.xcodeproj/project.pbxproj:
+
+ Add generic HTTP Request parsing functions to HTTPParsers.cpp.
+ Use out parameters to get values after parsing.
+
+ * platform/network/HTTPParsers.cpp:
+ (WebCore):
+ (WebCore::trimInputSample): taken from WebSocket parsing.
+ (WebCore::parseHTTPRequestLine): new code, parse a request line.
+ (WebCore::parseHTTPHeaders): taken from previous WebSocket parsing. Algorithm unchanged.
+ (WebCore::parseHTTPRequestBody): new code, just copy the date into the provided buffer.
+ * platform/network/HTTPParsers.h:
+ (WebCore):
+
+ This adds a general HTTPRequest class. Accessors for the
+ request method, url, httpVersion, headers, and data. You can
+ create an HTTPRequest using the constructor, or parse one
+ from a data buffer, such as one read from a socket.
+
+ * platform/network/HTTPRequest.cpp: Added.
+ (WebCore):
+ (WebCore::HTTPRequest::parseHTTPRequestFromBuffer): create an HTTPRequest by parsing data in a buffer.
+ (WebCore::HTTPRequest::parseRequestLine): helper to initialize members while parsing.
+ (WebCore::HTTPRequest::parseHeaders): helper to initialize members while parsing.
+ (WebCore::HTTPRequest::parseRequestBody): helper to initialize members while parsing.
+ (WebCore::HTTPRequest::HTTPRequest):
+ (WebCore::HTTPRequest::~HTTPRequest):
+ * platform/network/HTTPRequest.h: Added.
+ (WebCore):
+ (HTTPRequest):
+ (WebCore::HTTPRequest::create): create an empty request, or specify details.
+ (WebCore::HTTPRequest::requestMethod):
+ (WebCore::HTTPRequest::setRequestMethod):
+ (WebCore::HTTPRequest::url):
+ (WebCore::HTTPRequest::setURL):
+ (WebCore::HTTPRequest::body):
+ (WebCore::HTTPRequest::headerFields):
+ (WebCore::HTTPRequest::addHeaderField):
+
2012-04-03 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
[Qt] Add a missing inspector front-end image to resources.
Source/WebCore/platform/network/HTTPHeaderMap.h \
Source/WebCore/platform/network/HTTPParsers.cpp \
Source/WebCore/platform/network/HTTPParsers.h \
+ Source/WebCore/platform/network/HTTPRequest.cpp \
+ Source/WebCore/platform/network/HTTPRequest.h \
Source/WebCore/platform/network/HTTPValidation.cpp \
Source/WebCore/platform/network/HTTPValidation.h \
Source/WebCore/platform/network/MIMEHeader.cpp \
if (!m_document)
return;
if (m_identifier)
- InspectorInstrumentation::willSendWebSocketHandshakeRequest(m_document, m_identifier, m_handshake->clientHandshakeRequest());
+ InspectorInstrumentation::willSendWebSocketHandshakeRequest(m_document, m_identifier, *m_handshake->clientHandshakeRequest());
CString handshakeMessage = m_handshake->clientHandshakeMessage();
if (!handle->send(handshakeMessage.data(), handshakeMessage.length()))
fail("Failed to send WebSocket handshake.");
#include "CookieJar.h"
#include "Document.h"
#include "HTTPHeaderMap.h"
+#include "HTTPParsers.h"
#include "KURL.h"
#include "Logging.h"
#include "ScriptCallStack.h"
return builder.toString();
}
-static const size_t maxConsoleMessageSize = 128;
-static String trimConsoleMessage(const char* p, size_t len)
+static const size_t maxInputSampleSize = 128;
+static String trimInputSample(const char* p, size_t len)
{
- String s = String(p, std::min<size_t>(len, maxConsoleMessageSize));
- if (len > maxConsoleMessageSize)
+ String s = String(p, std::min<size_t>(len, maxInputSampleSize));
+ if (len > maxInputSampleSize)
s.append(horizontalEllipsis);
return s;
}
return msg;
}
-WebSocketHandshakeRequest WebSocketHandshake::clientHandshakeRequest() const
+PassRefPtr<WebSocketHandshakeRequest> WebSocketHandshake::clientHandshakeRequest() const
{
// Keep the following consistent with clientHandshakeMessage().
// FIXME: do we need to store m_secWebSocketKey1, m_secWebSocketKey2 and
// m_key3 in WebSocketHandshakeRequest?
- WebSocketHandshakeRequest request("GET", m_url);
+ RefPtr<WebSocketHandshakeRequest> request = WebSocketHandshakeRequest::create("GET", m_url);
if (m_useHixie76Protocol)
- request.addHeaderField("Upgrade", "WebSocket");
+ request->addHeaderField("Upgrade", "WebSocket");
else
- request.addHeaderField("Upgrade", "websocket");
- request.addHeaderField("Connection", "Upgrade");
- request.addHeaderField("Host", hostName(m_url, m_secure));
- request.addHeaderField("Origin", clientOrigin());
+ request->addHeaderField("Upgrade", "websocket");
+ request->addHeaderField("Connection", "Upgrade");
+ request->addHeaderField("Host", hostName(m_url, m_secure));
+ request->addHeaderField("Origin", clientOrigin());
if (!m_clientProtocol.isEmpty())
- request.addHeaderField("Sec-WebSocket-Protocol:", m_clientProtocol);
+ request->addHeaderField("Sec-WebSocket-Protocol", m_clientProtocol);
KURL url = httpURLForAuthenticationAndCookies();
if (m_context->isDocument()) {
Document* document = static_cast<Document*>(m_context);
String cookie = cookieRequestHeaderFieldValue(document, url);
if (!cookie.isEmpty())
- request.addHeaderField("Cookie", cookie);
+ request->addHeaderField("Cookie", cookie);
// Set "Cookie2: <cookie>" if cookies 2 exists for url?
}
if (m_useHixie76Protocol) {
- request.addHeaderField("Sec-WebSocket-Key1", m_hixie76SecWebSocketKey1);
- request.addHeaderField("Sec-WebSocket-Key2", m_hixie76SecWebSocketKey2);
- request.setKey3(m_hixie76Key3);
+ request->addHeaderField("Sec-WebSocket-Key1", m_hixie76SecWebSocketKey1);
+ request->addHeaderField("Sec-WebSocket-Key2", m_hixie76SecWebSocketKey2);
+ request->setKey3(m_hixie76Key3);
} else {
- request.addHeaderField("Sec-WebSocket-Key", m_secWebSocketKey);
- request.addHeaderField("Sec-WebSocket-Version", "13");
+ request->addHeaderField("Sec-WebSocket-Key", m_secWebSocketKey);
+ request->addHeaderField("Sec-WebSocket-Version", "13");
const String extensionValue = m_extensionDispatcher.createHeaderValue();
if (extensionValue.length())
- request.addHeaderField("Sec-WebSocket-Extensions", extensionValue);
+ request->addHeaderField("Sec-WebSocket-Extensions", extensionValue);
}
- return request;
+ return request.release();
}
void WebSocketHandshake::reset()
}
if (!space1 || !space2) {
- m_failureReason = "No response code found: " + trimConsoleMessage(header, lineLength - 2);
+ m_failureReason = "No response code found: " + trimInputSample(header, lineLength - 2);
return lineLength;
}
{
m_response.clearHeaderFields();
- Vector<char> name;
- Vector<char> value;
+ AtomicString name;
+ String value;
bool sawSecWebSocketAcceptHeaderField = false;
bool sawSecWebSocketProtocolHeaderField = false;
- for (const char* p = start; p < end; p++) {
- name.clear();
- value.clear();
-
- for (; p < end; p++) {
- switch (*p) {
- case '\r':
- if (name.isEmpty()) {
- if (p + 1 < end && *(p + 1) == '\n')
- return p + 2;
- m_failureReason = "CR doesn't follow LF at " + trimConsoleMessage(p, end - p);
- return 0;
- }
- m_failureReason = "Unexpected CR in name at " + trimConsoleMessage(name.data(), name.size());
- return 0;
- case '\n':
- m_failureReason = "Unexpected LF in name at " + trimConsoleMessage(name.data(), name.size());
- return 0;
- case ':':
- break;
- default:
- name.append(*p);
- continue;
- }
- if (*p == ':') {
- ++p;
- break;
- }
- }
+ const char* p = start;
+ for (; p < end; p++) {
+ size_t consumedLength = parseHTTPHeader(p, end - p, m_failureReason, name, value);
+ if (!consumedLength)
+ return 0;
+ p += consumedLength;
- for (; p < end && *p == 0x20; p++) { }
+ // Stop once we consumed an empty line.
+ if (name.isEmpty())
+ break;
- for (; p < end; p++) {
- switch (*p) {
- case '\r':
- break;
- case '\n':
- m_failureReason = "Unexpected LF in value at " + trimConsoleMessage(value.data(), value.size());
- return 0;
- default:
- value.append(*p);
- }
- if (*p == '\r') {
- ++p;
- break;
- }
- }
- if (p >= end || *p != '\n') {
- m_failureReason = "CR doesn't follow LF after value at " + trimConsoleMessage(p, end - p);
- return 0;
- }
- AtomicString nameStr = AtomicString::fromUTF8(name.data(), name.size());
- String valueStr = String::fromUTF8(value.data(), value.size());
- if (nameStr.isNull()) {
- m_failureReason = "Invalid UTF-8 sequence in header name";
- return 0;
- }
- if (valueStr.isNull()) {
- m_failureReason = "Invalid UTF-8 sequence in header value";
- return 0;
- }
- LOG(Network, "name=%s value=%s", nameStr.string().utf8().data(), valueStr.utf8().data());
// Sec-WebSocket-Extensions may be split. We parse and check the
// header value every time the header appears.
- if (equalIgnoringCase("sec-websocket-extensions", nameStr)) {
- if (!m_extensionDispatcher.processHeaderValue(valueStr)) {
+ if (equalIgnoringCase("sec-websocket-extensions", name)) {
+ if (!m_extensionDispatcher.processHeaderValue(value)) {
m_failureReason = m_extensionDispatcher.failureReason();
return 0;
}
- } else if (equalIgnoringCase("Sec-WebSocket-Accept", nameStr)) {
+ } else if (equalIgnoringCase("Sec-WebSocket-Accept", name)) {
if (sawSecWebSocketAcceptHeaderField) {
m_failureReason = "The Sec-WebSocket-Accept header MUST NOT appear more than once in an HTTP response";
return 0;
}
- m_response.addHeaderField(nameStr, valueStr);
+ m_response.addHeaderField(name, value);
sawSecWebSocketAcceptHeaderField = true;
- } else if (equalIgnoringCase("Sec-WebSocket-Protocol", nameStr)) {
+ } else if (equalIgnoringCase("Sec-WebSocket-Protocol", name)) {
if (sawSecWebSocketProtocolHeaderField) {
m_failureReason = "The Sec-WebSocket-Protocol header MUST NOT appear more than once in an HTTP response";
return 0;
}
- m_response.addHeaderField(nameStr, valueStr);
+ m_response.addHeaderField(name, value);
sawSecWebSocketProtocolHeaderField = true;
} else
- m_response.addHeaderField(nameStr, valueStr);
+ m_response.addHeaderField(name, value);
}
- ASSERT_NOT_REACHED();
- return 0;
+ return p;
}
bool WebSocketHandshake::checkResponseHeaders()
String clientLocation() const;
CString clientHandshakeMessage() const;
- WebSocketHandshakeRequest clientHandshakeRequest() const;
+ PassRefPtr<WebSocketHandshakeRequest> clientHandshakeRequest() const;
void reset();
void clearScriptExecutionContext();
}
WebSocketHandshakeRequest::WebSocketHandshakeRequest(const String& requestMethod, const KURL& url)
- : m_url(url)
- , m_requestMethod(requestMethod)
+ : HTTPRequest(requestMethod, url, HTTP_1_1)
{
}
{
}
-String WebSocketHandshakeRequest::requestMethod() const
-{
- return m_requestMethod;
-}
-
-KURL WebSocketHandshakeRequest::url() const
-{
- return m_url;
-}
-
-void WebSocketHandshakeRequest::addHeaderField(const char* name, const String& value)
-{
- m_headerFields.add(name, value);
-}
-
-const HTTPHeaderMap& WebSocketHandshakeRequest::headerFields() const
-{
- return m_headerFields;
-}
-
WebSocketHandshakeRequest::Key3 WebSocketHandshakeRequest::key3() const
{
return m_key3;
#if ENABLE(WEB_SOCKETS)
-#include "HTTPHeaderMap.h"
-#include "KURL.h"
-#include "PlatformString.h"
+#include "HTTPRequest.h"
namespace WebCore {
-class WebSocketHandshakeRequest {
+class WebSocketHandshakeRequest : public HTTPRequest {
public:
- WebSocketHandshakeRequest(const String& requestMethod, const KURL&);
+ static PassRefPtr<WebSocketHandshakeRequest> create(const String& requestMethod, const KURL& url) { return adoptRef(new WebSocketHandshakeRequest(requestMethod, url)); }
~WebSocketHandshakeRequest();
- String requestMethod() const;
- KURL url() const;
-
- const HTTPHeaderMap& headerFields() const;
- void addHeaderField(const char* name, const String& value);
-
struct Key3 {
unsigned char value[8];
void setKey3(const unsigned char key3[8]);
private:
- KURL m_url;
- String m_requestMethod;
- HTTPHeaderMap m_headerFields;
+ WebSocketHandshakeRequest(const String& requestMethod, const KURL&);
Key3 m_key3;
};
platform/network/FormDataBuilder.cpp \
platform/network/HTTPHeaderMap.cpp \
platform/network/HTTPParsers.cpp \
+ platform/network/HTTPRequest.cpp \
platform/network/HTTPValidation.cpp \
platform/network/MIMEHeader.cpp \
platform/network/NetworkStateNotifier.cpp \
platform/network/FormData.h \
platform/network/HTTPHeaderMap.h \
platform/network/HTTPParsers.h \
+ platform/network/HTTPRequest.h \
platform/network/HTTPValidation.h \
platform/network/HTTPStatusCodes.h \
platform/network/MIMESniffing.h \
'platform/network/HTTPHeaderMap.cpp',
'platform/network/HTTPParsers.cpp',
'platform/network/HTTPParsers.h',
+ 'platform/network/HTTPRequest.cpp',
+ 'platform/network/HTTPRequest.h',
'platform/network/HTTPValidation.cpp',
'platform/network/HTTPValidation.h',
'platform/network/MIMEHeader.cpp',
>
</File>
<File
+ RelativePath="..\platform\network\HTTPRequest.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\platform\network\HTTPRequest.h"
+ >
+ </File>
+ <File
RelativePath="..\platform\network\HTTPValidation.cpp"
>
</File>
A5ABB78713B904BC00F197E3 /* LineBreakIteratorPoolICU.h in Headers */ = {isa = PBXBuildFile; fileRef = A5ABB78613B904BC00F197E3 /* LineBreakIteratorPoolICU.h */; };
A5AFB34F115151A700B045CB /* StepRange.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5AFB34D115151A700B045CB /* StepRange.cpp */; };
A5AFB350115151A700B045CB /* StepRange.h in Headers */ = {isa = PBXBuildFile; fileRef = A5AFB34E115151A700B045CB /* StepRange.h */; };
+ A5D214B112E905510090F370 /* HTTPRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A5D214AE12E905510090F370 /* HTTPRequest.cpp */; };
+ A5D214B212E905510090F370 /* HTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = A5D214AF12E905510090F370 /* HTTPRequest.h */; };
A6148A6212E41D3A0044A784 /* DOMHTMLKeygenElementInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = A6148A6112E41D3A0044A784 /* DOMHTMLKeygenElementInternal.h */; };
A6148A6712E41D940044A784 /* DOMHTMLKeygenElement.h in Headers */ = {isa = PBXBuildFile; fileRef = A6148A6512E41D940044A784 /* DOMHTMLKeygenElement.h */; };
A6148A6812E41D940044A784 /* DOMHTMLKeygenElement.mm in Sources */ = {isa = PBXBuildFile; fileRef = A6148A6612E41D940044A784 /* DOMHTMLKeygenElement.mm */; };
A5AFB34E115151A700B045CB /* StepRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StepRange.h; sourceTree = "<group>"; };
A5C974CF11485FF10066F2AB /* KeyEventCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KeyEventCocoa.h; path = cocoa/KeyEventCocoa.h; sourceTree = "<group>"; };
A5C974D011485FF10066F2AB /* KeyEventCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = KeyEventCocoa.mm; path = cocoa/KeyEventCocoa.mm; sourceTree = "<group>"; };
+ A5D214AE12E905510090F370 /* HTTPRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPRequest.cpp; sourceTree = "<group>"; };
+ A5D214AF12E905510090F370 /* HTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPRequest.h; sourceTree = "<group>"; };
A6148A6112E41D3A0044A784 /* DOMHTMLKeygenElementInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMHTMLKeygenElementInternal.h; sourceTree = "<group>"; };
A6148A6512E41D940044A784 /* DOMHTMLKeygenElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMHTMLKeygenElement.h; sourceTree = "<group>"; };
A6148A6612E41D940044A784 /* DOMHTMLKeygenElement.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DOMHTMLKeygenElement.mm; sourceTree = "<group>"; };
514C765C0CE923A1007EF3CD /* HTTPHeaderMap.h */,
514C765D0CE923A1007EF3CD /* HTTPParsers.cpp */,
514C765E0CE923A1007EF3CD /* HTTPParsers.h */,
+ A5D214AE12E905510090F370 /* HTTPRequest.cpp */,
+ A5D214AF12E905510090F370 /* HTTPRequest.h */,
9B0FB18F140DB5790022588F /* HTTPValidation.cpp */,
9B0FB190140DB5790022588F /* HTTPValidation.h */,
37DDCD9213844FD50008B793 /* MIMEHeader.cpp */,
977B387A122883E900B81FF8 /* HTMLViewSourceParser.h in Headers */,
514C76710CE923A1007EF3CD /* HTTPHeaderMap.h in Headers */,
514C76730CE923A1007EF3CD /* HTTPParsers.h in Headers */,
+ A5D214B212E905510090F370 /* HTTPRequest.h in Headers */,
9B0FB192140DB5790022588F /* HTTPValidation.h in Headers */,
375CD232119D43C800A2A859 /* Hyphenation.h in Headers */,
B275356E0B053814002CE64F /* Icon.h in Headers */,
977B3879122883E900B81FF8 /* HTMLViewSourceParser.cpp in Sources */,
0B8C56D40F28627F000502E1 /* HTTPHeaderMap.cpp in Sources */,
514C76720CE923A1007EF3CD /* HTTPParsers.cpp in Sources */,
+ A5D214B112E905510090F370 /* HTTPRequest.cpp in Sources */,
9B0FB191140DB5790022588F /* HTTPValidation.cpp in Sources */,
371A67CB11C6C7DB00047B8B /* HyphenationCF.cpp in Sources */,
375CD23B119D44EA00A2A859 /* HyphenationMac.mm in Sources */,
* Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
* Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2011 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "config.h"
#include "HTTPParsers.h"
-#include "ResourceResponseBase.h"
#include "PlatformString.h"
+#include <wtf/DateMath.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringBuilder.h>
-#include <wtf/DateMath.h>
+#include <wtf/unicode/CharacterNames.h>
using namespace WTF;
return true;
}
+static const size_t maxInputSampleSize = 128;
+static String trimInputSample(const char* p, size_t length)
+{
+ String s = String(p, std::min<size_t>(length, maxInputSampleSize));
+ if (length > maxInputSampleSize)
+ s.append(horizontalEllipsis);
+ return s;
+}
+
ContentDispositionType contentDispositionType(const String& contentDisposition)
{
if (contentDisposition.isEmpty())
return true;
}
+// HTTP/1.1 - RFC 2616
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1
+// Request-Line = Method SP Request-URI SP HTTP-Version CRLF
+size_t parseHTTPRequestLine(const char* data, size_t length, String& failureReason, String& method, String& url, HTTPVersion& httpVersion)
+{
+ method = String();
+ url = String();
+ httpVersion = Unknown;
+
+ const char* space1 = 0;
+ const char* space2 = 0;
+ const char* p;
+ size_t consumedLength;
+
+ for (p = data, consumedLength = 0; consumedLength < length; p++, consumedLength++) {
+ if (*p == ' ') {
+ if (!space1)
+ space1 = p;
+ else if (!space2)
+ space2 = p;
+ } else if (*p == '\n')
+ break;
+ }
+
+ // Haven't finished header line.
+ if (consumedLength == length) {
+ failureReason = "Incomplete Request Line";
+ return 0;
+ }
+
+ // RequestLine does not contain 3 parts.
+ if (!space1 || !space2) {
+ failureReason = "Request Line does not appear to contain: <Method> <Url> <HTTPVersion>.";
+ return 0;
+ }
+
+ // The line must end with "\r\n".
+ const char* end = p + 1;
+ if (*(end - 2) != '\r') {
+ failureReason = "Request line does not end with CRLF";
+ return 0;
+ }
+
+ // Request Method.
+ method = String(data, space1 - data); // For length subtract 1 for space, but add 1 for data being the first character.
+
+ // Request URI.
+ url = String(space1 + 1, space2 - space1 - 1); // For length subtract 1 for space.
+
+ // HTTP Version.
+ String httpVersionString(space2 + 1, end - space2 - 3); // For length subtract 1 for space, and 2 for "\r\n".
+ if (httpVersionString.length() != 8 || !httpVersionString.startsWith("HTTP/1."))
+ httpVersion = Unknown;
+ else if (httpVersionString[7] == '0')
+ httpVersion = HTTP_1_0;
+ else if (httpVersionString[7] == '1')
+ httpVersion = HTTP_1_1;
+ else
+ httpVersion = Unknown;
+
+ return end - data;
+}
+
+size_t parseHTTPHeader(const char* start, size_t length, String& failureReason, AtomicString& nameStr, String& valueStr)
+{
+ const char* p = start;
+ const char* end = start + length;
+
+ Vector<char> name;
+ Vector<char> value;
+ nameStr = AtomicString();
+ valueStr = String();
+
+ for (; p < end; p++) {
+ switch (*p) {
+ case '\r':
+ if (name.isEmpty()) {
+ if (p + 1 < end && *(p + 1) == '\n')
+ return (p + 2) - start;
+ failureReason = "CR doesn't follow LF at " + trimInputSample(p, end - p);
+ return 0;
+ }
+ failureReason = "Unexpected CR in name at " + trimInputSample(name.data(), name.size());
+ return 0;
+ case '\n':
+ failureReason = "Unexpected LF in name at " + trimInputSample(name.data(), name.size());
+ return 0;
+ case ':':
+ break;
+ default:
+ name.append(*p);
+ continue;
+ }
+ if (*p == ':') {
+ ++p;
+ break;
+ }
+ }
+
+ for (; p < end && *p == 0x20; p++) { }
+
+ for (; p < end; p++) {
+ switch (*p) {
+ case '\r':
+ break;
+ case '\n':
+ failureReason = "Unexpected LF in value at " + trimInputSample(value.data(), value.size());
+ return 0;
+ default:
+ value.append(*p);
+ }
+ if (*p == '\r') {
+ ++p;
+ break;
+ }
+ }
+ if (p >= end || *p != '\n') {
+ failureReason = "CR doesn't follow LF after value at " + trimInputSample(p, end - p);
+ return 0;
+ }
+ nameStr = AtomicString::fromUTF8(name.data(), name.size());
+ valueStr = String::fromUTF8(value.data(), value.size());
+ if (nameStr.isNull()) {
+ failureReason = "Invalid UTF-8 sequence in header name";
+ return 0;
+ }
+ if (valueStr.isNull()) {
+ failureReason = "Invalid UTF-8 sequence in header value";
+ return 0;
+ }
+ return p - start;
+}
+
+size_t parseHTTPRequestBody(const char* data, size_t length, Vector<unsigned char>& body)
+{
+ body.clear();
+ body.append(data, length);
+
+ return length;
+}
+
}
/*
* Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
* Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2011 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#define HTTPParsers_h
#include <wtf/Forward.h>
+#include <wtf/Vector.h>
namespace WebCore {
+class HTTPHeaderMap;
class ResourceResponseBase;
enum XSSProtectionDisposition {
// -1 could be set to one of the return parameters to indicate the value is not specified.
bool parseRange(const String&, long long& rangeOffset, long long& rangeEnd, long long& rangeSuffixLength);
+// Parsing Complete HTTP Messages.
+enum HTTPVersion { Unknown, HTTP_1_0, HTTP_1_1 };
+size_t parseHTTPRequestLine(const char* data, size_t length, String& failureReason, String& method, String& url, HTTPVersion&);
+size_t parseHTTPHeader(const char* data, size_t length, String& failureReason, AtomicString& nameStr, String& valueStr);
+size_t parseHTTPRequestBody(const char* data, size_t length, Vector<unsigned char>& body);
+
}
#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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 APPLE INC. ``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 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.
+ */
+
+#include "config.h"
+#include "HTTPRequest.h"
+
+#include <wtf/text/CString.h>
+
+namespace WebCore {
+
+PassRefPtr<HTTPRequest> HTTPRequest::parseHTTPRequestFromBuffer(const char* data, size_t length, String& failureReason)
+{
+ if (!length) {
+ failureReason = "No data to parse.";
+ return 0;
+ }
+
+ // Request we will be building.
+ RefPtr<HTTPRequest> request = HTTPRequest::create();
+
+ // Advance a pointer through the data as needed.
+ const char* pos = data;
+ size_t remainingLength = length;
+
+ // 1. Parse Method + URL.
+ size_t requestLineLength = request->parseRequestLine(pos, remainingLength, failureReason);
+ if (!requestLineLength)
+ return 0;
+ pos += requestLineLength;
+ remainingLength -= requestLineLength;
+
+ // 2. Parse HTTP Headers.
+ size_t headersLength = request->parseHeaders(pos, remainingLength, failureReason);
+ if (!headersLength)
+ return 0;
+ pos += headersLength;
+ remainingLength -= headersLength;
+
+ // 3. Parse HTTP Data.
+ size_t dataLength = request->parseRequestBody(pos, remainingLength);
+ pos += dataLength;
+ remainingLength -= dataLength;
+
+ // We should have processed the entire input.
+ ASSERT(!remainingLength);
+ return request.release();
+}
+
+size_t HTTPRequest::parseRequestLine(const char* data, size_t length, String& failureReason)
+{
+ String url;
+ size_t result = parseHTTPRequestLine(data, length, failureReason, m_requestMethod, url, m_httpVersion);
+ m_url = KURL(KURL(), url);
+ return result;
+}
+
+size_t HTTPRequest::parseHeaders(const char* data, size_t length, String& failureReason)
+{
+ const char* p = data;
+ const char* end = data + length;
+ AtomicString name;
+ String value;
+ for (; p < data + length; p++) {
+ size_t consumedLength = parseHTTPHeader(p, end - p, failureReason, name, value);
+ if (!consumedLength)
+ return 0;
+ p += consumedLength;
+ if (name.isEmpty())
+ break;
+ m_headerFields.add(name, value);
+ }
+ return p - data;
+}
+
+size_t HTTPRequest::parseRequestBody(const char* data, size_t length)
+{
+ return parseHTTPRequestBody(data, length, m_body);
+}
+
+HTTPRequest::HTTPRequest()
+ : m_httpVersion(Unknown)
+{
+}
+
+HTTPRequest::HTTPRequest(const String& requestMethod, const KURL& url, HTTPVersion version)
+ : m_url(url)
+ , m_httpVersion(version)
+ , m_requestMethod(requestMethod)
+{
+}
+
+HTTPRequest::~HTTPRequest()
+{
+}
+
+} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2011 Apple Inc. All Rights Reserved.
+ *
+ * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 THE COPYRIGHT
+ * OWNER 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.
+ */
+
+#ifndef HTTPRequest_h
+#define HTTPRequest_h
+
+#include "HTTPHeaderMap.h"
+#include "HTTPParsers.h"
+#include "KURL.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class HTTPRequest : public RefCounted<HTTPRequest> {
+public:
+ static PassRefPtr<HTTPRequest> create() { return adoptRef(new HTTPRequest()); }
+ static PassRefPtr<HTTPRequest> create(const String& requestMethod, const KURL& url, HTTPVersion version) { return adoptRef(new HTTPRequest(requestMethod, url, version)); }
+ static PassRefPtr<HTTPRequest> parseHTTPRequestFromBuffer(const char* data, size_t length, String& failureReason);
+ virtual ~HTTPRequest();
+
+ String requestMethod() const { return m_requestMethod; }
+ void setRequestMethod(const String& method) { m_requestMethod = method; }
+
+ KURL url() const { return m_url; }
+ void setURL(const KURL& url) { m_url = url; }
+
+ const Vector<unsigned char>& body() const { return m_body; }
+
+ const HTTPHeaderMap& headerFields() const { return m_headerFields; }
+ void addHeaderField(const AtomicString& name, const String& value) { m_headerFields.add(name, value); }
+ void addHeaderField(const char* name, const String& value) { m_headerFields.add(name, value); }
+
+protected:
+ HTTPRequest();
+ HTTPRequest(const String& requestMethod, const KURL&, HTTPVersion);
+
+ // Parsing helpers.
+ size_t parseRequestLine(const char* data, size_t length, String& failureReason);
+ size_t parseHeaders(const char* data, size_t length, String& failureReason);
+ size_t parseRequestBody(const char* data, size_t length);
+
+ KURL m_url;
+ HTTPVersion m_httpVersion;
+ String m_requestMethod;
+ HTTPHeaderMap m_headerFields;
+ Vector<unsigned char> m_body;
+};
+
+} // namespace WebCore
+
+#endif // HTTPRequest_h