| Index: WebCore/websockets/WebSocketResponse.cpp
|
| diff --git a/WebCore/websockets/WebSocketResponse.cpp b/WebCore/websockets/WebSocketResponse.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c00c6c0d5934fa1c14fb738d0fa8d8068a1d0f6c
|
| --- /dev/null
|
| +++ b/WebCore/websockets/WebSocketResponse.cpp
|
| @@ -0,0 +1,230 @@
|
| +/*
|
| + * Copyright (C) 2009 Google 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.
|
| + */
|
| +
|
| +#include "WebSocketResponse.h"
|
| +
|
| +#include "CString.h"
|
| +#include "Logging.h"
|
| +
|
| +#undef LOG
|
| +#define LOG(channel, ...) do { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } while (0);
|
| +
|
| +namespace {
|
| +
|
| +bool hadResponseHeader(const char *start, const char *end)
|
| +{
|
| + for (const char *p = start; p && p < end; p++) {
|
| + p = static_cast<const char *>(memchr(p, '\r', end - p));
|
| + if (!p) {
|
| + return false;
|
| + }
|
| + if (p + 3 < end && *(p + 1) == '\n' && *(p + 2) == '\r' && *(p + 3) == '\n') {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +}
|
| +
|
| +namespace WebCore {
|
| +
|
| +const char webSocketResponseHeader[] = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
|
| + "Upgrade: WebSocket\r\n"
|
| + "Connection: Upgrade\r\n";
|
| +
|
| +WebSocketResponse::WebSocketResponse()
|
| + : m_valid(false)
|
| +{
|
| +}
|
| +
|
| +WebSocketResponse::~WebSocketResponse()
|
| +{
|
| +}
|
| +
|
| +const char* WebSocketResponse::parseHeader(const char* start, const char* end, Vector<std::pair<String, String> >* headers)
|
| +{
|
| + Vector<char> name;
|
| + Vector<char> value;
|
| + for (const char* p = start; p < end; p++) {
|
| + name.clear();
|
| + value.clear();
|
| + // LOG(Network, "parseHeader next %s", p);
|
| + for (; p < end; p++) {
|
| + switch (*p) {
|
| + case '\r':
|
| + if (name.isEmpty()) {
|
| + if (p + 1 < end && *(p + 1) == '\n')
|
| + return p + 2;
|
| + else {
|
| + LOG(Network, "CF doesn't follow LF p=%p end=%p", p, end);
|
| + return NULL;
|
| + }
|
| + }
|
| + LOG(Network, "Unexpected CR in name");
|
| + return NULL;
|
| + case '\n':
|
| + LOG(Network, "Unexpected LF in name");
|
| + return NULL;
|
| + case ':':
|
| + break;
|
| + default:
|
| + if (*p >= 0x41 && *p <= 0x5a) {
|
| + name.append(*p + 0x20);
|
| + } else {
|
| + name.append(*p);
|
| + }
|
| + continue;
|
| + }
|
| + if (*p == ':') {
|
| + // LOG(Network, "colon found after name=%s", name.data());
|
| + ++p;
|
| + break;
|
| + }
|
| + }
|
| + // LOG(Network, "skip space: %s", p);
|
| + for (; p < end && *p == 0x20; p++)
|
| + ;
|
| + // LOG(Network, "parse value: %s", p);
|
| + for (; p < end; p++) {
|
| + switch (*p) {
|
| + case '\r':
|
| + break;
|
| + case '\n':
|
| + LOG(Network, "Unexpected LF in value");
|
| + return NULL;
|
| + default:
|
| + value.append(*p);
|
| + }
|
| + if (*p == '\r') {
|
| + // LOG(Network, "CR found after value=%s", value.data());
|
| + ++p;
|
| + break;
|
| + }
|
| + }
|
| + if (p >= end || *p != '\n') {
|
| + LOG(Network, "CR doesn't follow LF after value p=%p end=%p", p, end);
|
| + return NULL;
|
| + }
|
| + String name_str = String::fromUTF8(name.data(), name.size());
|
| + String value_str = String::fromUTF8(value.data(), value.size());
|
| + LOG(Network, "name=%s value=%s", name_str.utf8().data(), value_str.utf8().data());
|
| + headers->append(std::make_pair(name_str, value_str));
|
| + }
|
| + LOG(Network, "Unexpected end of header");
|
| + return NULL;
|
| +}
|
| +
|
| +int WebSocketResponse::readHandshakeResponse(const char* header, int len)
|
| +{
|
| + m_valid = false;
|
| + if (len < sizeof(webSocketResponseHeader)) {
|
| + LOG(Network, "short response header len=%d", len);
|
| + return 0;
|
| + }
|
| + if (memcmp(header, webSocketResponseHeader, sizeof(webSocketResponseHeader) - 1) != 0) {
|
| + LOG(Network, "Mismatch response header: %s", header);
|
| + return len;
|
| + }
|
| + const char *p = header + sizeof(webSocketResponseHeader) - 1;
|
| + const char *end = header + len + 1;
|
| + if (!hadResponseHeader(p, end)) {
|
| + LOG(Network, "incomplete response header len=%d", len);
|
| + return 0;
|
| + }
|
| + Vector<std::pair<String, String> > headers;
|
| + p = parseHeader(p, end, &headers);
|
| + if (!p) {
|
| + LOG(Network, "parseHeader failed");
|
| + return len;
|
| + }
|
| + // _Headers processing_
|
| + for (Vector<std::pair<String, String> >::iterator it = headers.begin(); it != headers.end(); ++it) {
|
| + if (it->first == "websocket-origin") {
|
| + if (!m_origin.isEmpty())
|
| + return len;
|
| + m_origin = it->second;
|
| + } else if (it->first == "websocket-location") {
|
| + if (!m_location.isEmpty())
|
| + return len;
|
| + m_location = it->second;
|
| + } else if (it->first == "websocket-protocol") {
|
| + if (!m_protocol.isEmpty())
|
| + return len;
|
| + m_protocol = it->second;
|
| + }
|
| + }
|
| + if (m_origin.isEmpty() || m_location.isEmpty())
|
| + return len;
|
| + m_valid = true;
|
| + return p - header;
|
| +}
|
| +
|
| +bool WebSocketResponse::isValidHeader() const
|
| +{
|
| + return m_valid;
|
| +}
|
| +
|
| +void WebSocketResponse::setIsValidHeader(bool valid)
|
| +{
|
| + m_valid = valid;
|
| +}
|
| +
|
| +const String& WebSocketResponse::websocket_origin() const
|
| +{
|
| + return m_origin;
|
| +}
|
| +
|
| +void WebSocketResponse::setWebSocketOrigin(const String& websocket_origin)
|
| +{
|
| + m_origin = websocket_origin;
|
| +}
|
| +
|
| +const String& WebSocketResponse::websocket_location() const
|
| +{
|
| + return m_location;
|
| +}
|
| +
|
| +void WebSocketResponse::setWebSocketLocation(const String& websocket_location)
|
| +{
|
| + m_location = websocket_location;
|
| +}
|
| +
|
| +const String& WebSocketResponse::websocket_protocol() const
|
| +{
|
| + return m_protocol;
|
| +}
|
| +
|
| +void WebSocketResponse::setWebSocketProtocol(const String& websocket_protocol)
|
| +{
|
| + m_protocol = websocket_protocol;
|
| +}
|
| +
|
| +} // namespace WebCore
|
|
|