/** ** \file AjpBaseSocket.cpp ** \date 2007-10-05 ** \author grymse@alhem.net **/ /* Copyright (C) 2007 Anders Hedstrom This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef _MSC_VER #pragma warning(disable:4786) #endif #include "AjpBaseSocket.h" #include "ajp13.h" #ifdef SOCKETS_NAMESPACE namespace SOCKETS_NAMESPACE { #endif #ifdef _DEBUG #define DEB(x) x #else #define DEB(x) #endif // --------------------------------------------------------------------------- AjpBaseSocket::Initializer AjpBaseSocket::Init; // --------------------------------------------------------------------------- AjpBaseSocket::Initializer::Initializer() { Header[HTTP_REQUEST_ACCEPT] = "accept"; Header[HTTP_REQUEST_ACCEPT_CHARSET] = "accept-charset"; Header[HTTP_REQUEST_ACCEPT_ENCODING] = "accept-encoding"; Header[HTTP_REQUEST_ACCEPT_LANGUAGE] = "accept-language"; Header[HTTP_REQUEST_AUTHORIZATION] = "authorization"; Header[HTTP_REQUEST_CONNECTION] = "connection"; Header[HTTP_REQUEST_CONTENT_TYPE] = "content-type"; Header[HTTP_REQUEST_CONTENT_LENGTH] = "content-length"; Header[HTTP_REQUEST_COOKIE] = "cookie"; Header[HTTP_REQUEST_COOKIE2] = "cookie2"; Header[HTTP_REQUEST_HOST] = "host"; Header[HTTP_REQUEST_PRAGMA] = "pragma"; Header[HTTP_REQUEST_REFERER] = "referer"; Header[HTTP_REQUEST_USER_AGENT] = "user-agent"; Method[HTTP_METHOD_OPTIONS] = "OPTIONS"; Method[HTTP_METHOD_GET] = "GET"; Method[HTTP_METHOD_HEAD] = "HEAD"; Method[HTTP_METHOD_POST] = "POST"; Method[HTTP_METHOD_PUT] = "PUT"; Method[HTTP_METHOD_DELETE] = "DELETE"; Method[HTTP_METHOD_TRACE] = "TRACE"; Method[HTTP_METHOD_PROPFIND] = "PROPFIND"; Method[HTTP_METHOD_PROPPATCH] = "PROPPATCH"; Method[HTTP_METHOD_MKCOL] = "MKCOL"; Method[HTTP_METHOD_COPY] = "COPY"; Method[HTTP_METHOD_MOVE] = "MOVE"; Method[HTTP_METHOD_LOCK] = "LOCK"; Method[HTTP_METHOD_UNLOCK] = "UNLOCK"; Method[HTTP_METHOD_ACL] = "ACL"; Method[HTTP_METHOD_REPORT] = "REPORT"; Method[HTTP_METHOD_VERSION_CONTROL] = "VERSION_CONTROL"; // with a dash "VERSION-CONTROL" Method[HTTP_METHOD_CHECKIN] = "CHECKIN"; Method[HTTP_METHOD_CHECKOUT] = "CHECKOUT"; Method[HTTP_METHOD_UNCHECKOUT] = "UNCHECKOUT"; Method[HTTP_METHOD_SEARCH] = "SEARCH"; Method[HTTP_METHOD_MKWORKSPACE] = "MKWORKSPACE"; Method[HTTP_METHOD_UPDATE] = "UPDATE"; Method[HTTP_METHOD_LABEL] = "LABEL"; Method[HTTP_METHOD_MERGE] = "MERGE"; Method[HTTP_METHOD_BASELINE_CONTROL] = "BASELINE_CONTROL"; Method[HTTP_METHOD_MKACTIVITY] = "MKACTIVITY"; Attribute[ATTR_CONTEXT] = "context"; Attribute[ATTR_SERVLET_PATH] = "servlet_path"; Attribute[ATTR_REMOTE_USER] = "remote_user"; Attribute[ATTR_AUTH_TYPE] = "auth_type"; Attribute[ATTR_QUERY_STRING] = "query_string"; Attribute[ATTR_ROUTE] = "route"; Attribute[ATTR_SSL_CERT] = "ssl_cert"; Attribute[ATTR_SSL_CIPHER] = "ssl_cipher"; Attribute[ATTR_SSL_SESSION] = "ssl_session"; Attribute[ATTR_SSL_KEY_SIZE] = "ssl_key_size"; Attribute[ATTR_SECRET] = "secret"; Attribute[ATTR_STORED_METHOD] = "stored_method"; ResponseHeader["content-type"] = 0xa001; ResponseHeader["content-language"] = 0xa002; ResponseHeader["content-length"] = 0xa003; ResponseHeader["date"] = 0xa004; ResponseHeader["last-modified"] = 0xa005; ResponseHeader["location"] = 0xa006; ResponseHeader["set-cookie"] = 0xa007; ResponseHeader["set-cookie2"] = 0xa008; ResponseHeader["servlet-engine"] = 0xa009; ResponseHeader["status"] = 0xa00a; ResponseHeader["www-authenticate"] = 0xa00b; } // --------------------------------------------------------------------------- AjpBaseSocket::AjpBaseSocket(ISocketHandler& h) : TcpSocket(h) , m_state(0) , m_length(4) , m_ptr(0) { } // --------------------------------------------------------------------------- void AjpBaseSocket::OnRawData(const char *buf, size_t sz) { DEB(fprintf(stderr, "OnRawData: %d bytes\n", sz);) size_t ptr = 0; while (true) { size_t left = sz - ptr; DEB(fprintf(stderr, " left: %d bytes\n", left); fprintf(stderr, " state: %d\n", m_state);) switch (m_state) { case 0: { size_t missing = m_length - m_ptr; short len = (short)(missing < left ? missing : left); memcpy(m_message + m_ptr, buf + ptr, len); m_ptr += len; ptr += len; if (m_ptr < m_length) { return; // read more } int p = 0; short id = get_integer(m_message, p); short length = get_integer(m_message, p); OnHeader(id, length); m_state = 1; m_length = length; m_ptr = 0; // bytes in m_message } break; case 1: { size_t missing = m_length - m_ptr; short len = (short)(missing < left ? missing : left); memcpy(m_message + m_ptr, buf + ptr, len); m_ptr += len; ptr += len; if (m_ptr < m_length) { return; // read more } OnPacket(m_message, m_ptr); m_state = 0; m_length = 4; m_ptr = 0; } break; } } } // --------------------------------------------------------------------------- unsigned char AjpBaseSocket::get_byte(const char *buf, int& ptr) { return (unsigned char)buf[ptr++]; } // --------------------------------------------------------------------------- bool AjpBaseSocket::get_boolean(const char *buf, int& ptr) { return ( (unsigned char)buf[ptr++] & 1) == 1 ? true : false; } // --------------------------------------------------------------------------- short AjpBaseSocket::get_integer(const char *buf, int& ptr) { short n; memcpy(&n, buf + ptr, 2); ptr += 2; return ntohs(n); } // --------------------------------------------------------------------------- std::string AjpBaseSocket::get_string(const char *buf, int& ptr) { short len = get_integer(buf, ptr); if (len != -1) { std::string tmp = buf + ptr; ptr += len; ptr++; // skip trailing 0x0 tmp.resize(len); return tmp; } return ""; } // --------------------------------------------------------------------------- void AjpBaseSocket::put_byte(char *buf, int& ptr, unsigned char zz) { buf[ptr++] = zz; } // --------------------------------------------------------------------------- void AjpBaseSocket::put_boolean(char *buf, int& ptr, bool zz) { buf[ptr++] = zz ? 1 : 0; } // --------------------------------------------------------------------------- void AjpBaseSocket::put_integer(char *buf, int& ptr, short zz) { short tmp = htons(zz); memcpy(buf + ptr, &tmp, 2); ptr += 2; } // --------------------------------------------------------------------------- void AjpBaseSocket::put_string(char *buf, int& ptr, const std::string& zz) { put_integer(buf, ptr, (short)zz.size() ); memcpy(buf + ptr, zz.c_str(), zz.size()); ptr += (int)zz.size(); put_byte(buf, ptr, 0); } #ifdef SOCKETS_NAMESPACE } // namespace SOCKETS_NAMESPACE { #endif