示例#1
0
VOID CWebSocketProtocol::Translate(CConnectionSession<CWebSocketProtocol> &pConn, BYTE *data, DWORD dataLength)
{
	if (dataLength < 0 || ((dataLength + mRemainLength) > MAX_PACKET_BUFFER_LENGTH))
	{
		//如果超出缓冲区长度,视为错误包
		mRemainLength = 0;
		ZeroMemory(mDataBuffer, MAX_PACKET_BUFFER_LENGTH);
		return;
	}
	CopyMemory(mDataBuffer + mRemainLength, data, dataLength);
	mRemainLength += dataLength;

	if (!mIshandShaked)		//如果还没握手,进行握手
	{
		HttpRequestHeader  RequestHeader;
		RequestHeader.Input(mDataBuffer, mRemainLength);
		if (RequestHeader.Complete())
		{
			HandShake(RequestHeader, pConn);
		}
	}
	else 
	{
		//已握手则分析数据包,调用Handle方法
		DWORD64 PacketLength;
		while((this->*GetPacket)(pConn, PacketLength))
		{
			if (!mPacketBuffer) return;
			mPacketBuffer[PacketLength] = '\0';
			if (pConn.GetHandle())
			pConn.GetHandle()->Handle((char *)mPacketBuffer);
		}
	}
}
void HttpConnectionHandler::onRequestArrive(HttpRequestHeader& header, string& body_str)
{
    base::ErrorCode ec;
    if (sp_stub_dispatcher_)
        sp_stub_dispatcher_->invokeMethod(
            boost::static_pointer_cast<HttpConnectionHandler>(this->shared_from_this()),
            header, body_str, &ec);
    else
        ec = base::http::EC_HTTP_SERVICE_INTERNAL_ERROR;

    if (ec)
    {
        sendErrorMessage(header, &ec);
        LOG(error, "process request (" << header.getPath() << ") failed! " << ec);
        close();
    }
}
示例#3
0
/*
  Forward the HTTP requesto to another server.

  \param td The HTTP thread context.
  \param scriptpath Not used.
  \param exec The remote server Url.
  \param execute Not used.
  \param onlyHeader Specify if send only the HTTP header.
 */
int Proxy::send (HttpThreadContext *td, const char* scriptpath,
                 const char* exec, bool execute, bool onlyHeader)
{
  Url destUrl (exec, 80);
  ConnectionPtr con = NULL;
  Socket *sock;
  FiltersChain chain;
  HttpRequestHeader req;
  size_t nbw;
  bool keepalive = false;

  for (HashMap<string, HttpRequestHeader::Entry*>::Iterator it =
         td->request.begin (); it != td->request.end (); it++)
    {
      HttpRequestHeader::Entry *e = *it;
      req.setValue (e->name.c_str (), e->value.c_str ());
    }

  if (stringcmpi (destUrl.getProtocol (), "http"))
    {
      td->connection->host->warningsLogWrite
        ("Proxy: %s is not a supported protocol",
         destUrl.getProtocol ().c_str ());
      return td->http->raiseHTTPError (500);
    }

  try
    {
      req.ver.assign ("HTTP/1.1");
      req.cmd.assign (td->request.cmd);

      if (destUrl.getResource ()[0] == '\0' && td->pathInfo[0] == '\0')
        req.uri = "/";
      else
        {
          req.uri = destUrl.getResource ();
          req.uri.append (td->pathInfo);
        }
      if (td->request.uriOpts.length ())
        {
          req.uri.append ("?");
          req.uri.append (td->request.uriOpts);
        }

      req.setValue ("Connection", "keep-alive");
      if (td->request.uriOptsPtr)
        {
          char buffer[32];
          size_t size = td->inputData.getFileSize ();
          sprintf (buffer, "%u", size);
          req.setValue ("Content-Length", buffer);
        }

      ostringstream host;
      host << destUrl.getHost ();
      if (destUrl.getPort () != 80 )
        host << ":" << destUrl.getPort ();

      req.setValue ("Host", host.str ().c_str ());

      string xForwardedFor;
      td->request.getValue ("X-Forwarded-For", &xForwardedFor);
      if (xForwardedFor.size ())
        xForwardedFor.append (", ");
      xForwardedFor.append (td->connection->getIpAddr ());
      req.setValue ("X-Forwarded-For", xForwardedFor.c_str ());

      con = getConnection (destUrl.getHost ().c_str (), destUrl.getPort ());
      if (! con)
        return td->http->raiseHTTPError (500);

      sock = con->socket;

      u_long hdrLen =
        HttpHeaders::buildHTTPRequestHeader (td->auxiliaryBuffer->getBuffer (),
                                             &req);


      sock->write (td->auxiliaryBuffer->getBuffer (), hdrLen, &nbw);

      if (td->request.uriOptsPtr)
        td->inputData.fastCopyToSocket (sock, 0, td->auxiliaryBuffer, &nbw);

      chain.setStream (td->connection->socket);
      if (td->mime)
        Server::getInstance ()->getFiltersFactory ()->chain (&chain,
                                                             td->mime->filters,
                                                             td->connection->socket,
                                                             &nbw,
                                                             1);


      flushToClient (td, *sock, chain, onlyHeader, &keepalive);

      chain.clearAllFilters ();

      addConnection (con, destUrl.getHost ().c_str (), destUrl.getPort (),
                     keepalive);

      req.free ();
    }
  catch (exception & e)
    {
      if (con)
        addConnection (con, destUrl.getHost ().c_str (), destUrl.getPort (),
                       false);
      chain.clearAllFilters ();
      return td->http->raiseHTTPError (500);
    }

  return HttpDataHandler::RET_OK;
}
示例#4
0
int DeviceDiscoverer::discover(
   DeviceList& devices, const char* searchTarget, uint32_t timeout, int count)
{
   int rval = -1;

   // prepare device list
   devices->setType(Array);
   devices->clear();

   // create SSDP request
   HttpRequestHeader requestHeader;
   createRequest(searchTarget, &requestHeader);

   // create socket for sending request
   DatagramSocket socket;

   // bind to any available port
   InternetAddressRef localAddr = new InternetAddress("0.0.0.0", 0);
   if(socket.bind(&(*localAddr)))
   {
      // create the group address
      InternetAddressRef groupAddr = new InternetAddress(
         SSDP_MULTICAST_ADDRESS, SSDP_MULTICAST_PORT);

      // create and send discover request datagram
      DatagramRef request = new Datagram(groupAddr);
      request->assignString(requestHeader.toString().c_str());
      MO_CAT_DEBUG(MO_UPNP_CAT, "Sending UPnP request:\n%s",
         requestHeader.toString().c_str());
      if(socket.send(request))
      {
         // no devices yet
         rval = 0;

         // use timer to comply with user-supplied timeout
         Timer timer;
         timer.start();
         uint32_t remaining = timeout;
         InternetAddressRef addr = new InternetAddress();
         while(rval >= 0 && remaining > 0 && (count == 0 || rval < count))
         {
            // set receive timeout and try to get ssdp responses
            socket.setReceiveTimeout(remaining);

            DatagramRef response = new Datagram(addr);
            response->getBuffer()->resize(2048);
            if(!socket.receive(response))
            {
               // check last exception
               ExceptionRef e = Exception::get();
               if(e->isType("monarch.net.SocketTimeout"))
               {
                  MO_CAT_DEBUG(MO_UPNP_CAT, "UPnP request timed out.");

                  // exception indicates timed out
                  remaining = 0;
               }
               else
               {
                  MO_CAT_ERROR(MO_UPNP_CAT,
                     "UPnP request error: %s",
                     JsonWriter::writeToString(
                        Exception::getAsDynamicObject()).c_str());

                  // some error other than a timeout
                  rval = -1;
               }
            }
            else
            {
               // parse ssdp response
               MO_CAT_DEBUG(MO_UPNP_CAT, "Received UPnP response:\n%s",
                  response->getString().c_str());
               Device device = parseDevice(response->getString().c_str());
               if(device.isNull())
               {
                  MO_CAT_ERROR(MO_UPNP_CAT,
                     "UPnP response parse error: %s",
                     JsonWriter::writeToString(
                        Exception::getAsDynamicObject()).c_str());

                  // error in parsing
                  rval = -1;
               }
               else
               {
                  MO_CAT_DEBUG(MO_UPNP_CAT,
                     "Found UPnP device: %s",
                     JsonWriter::writeToString(device).c_str());

                  // another device found
                  ++rval;
                  devices->append(device);

                  // update remaining time (must be within 32-bit integer range)
                  remaining = (uint32_t)timer.getRemainingMilliseconds(timeout);
               }
            }
         }
      }
   }

   return rval;
}
示例#5
0
static void runHttpHeaderTest(TestRunner& tr)
{
   tr.group("HttpHeader");

   tr.test("Bicapitalization");
   {
      // test bicapitalization of http headers
      const char* tests[] = {
         "", "",
         "a", "A",
         "-", "-",
         "a--a", "A--A",
         "-aa-", "-Aa-",
         "-aa", "-Aa",
         "aa-", "Aa-",
         "aaa-zzz", "Aaa-Zzz",
         "ThIs-a-BICaPitAlized-hEADer", "This-A-Bicapitalized-Header",
         "Message-ID", "Message-Id",
         NULL
      };
      for(int i = 0; tests[i] != NULL; i +=2)
      {
         char* bic = strdup(tests[i]);
         HttpHeader::biCapitalize(bic);
         assertStrCmp(bic, tests[i+1]);
         free(bic);
      }
   }
   tr.passIfNoException();

   tr.test("HttpRequestHeader parse");
   {
      HttpRequestHeader header;
      header.setDate();
      header.setMethod("GET");
      header.setPath("/");
      header.setVersion("HTTP/1.1");
      header.setField("host", "localhost:80");
      header.setField("Content-Type", "text/html");
      header.setField("Connection", "close");

      string date;
      string expect;
      expect.append("GET / HTTP/1.1\r\n");
      expect.append("Connection: close\r\n");
      expect.append("Content-Type: text/html\r\n");
      expect.append("Date: ");
      header.getField("Date", date);
      expect.append(date);
      expect.append("\r\n");
      expect.append("Host: localhost:80\r\n");
      expect.append("\r\n");

      string str = header.toString();
      assertStrCmp(str.c_str(), expect.c_str());

      HttpRequestHeader header2;
      header2.parse(str);

      string str2 = header2.toString();
      assertStrCmp(str2.c_str(), expect.c_str());
   }
   tr.passIfNoException();

   tr.test("HttpResponseHeader parse");
   {
      HttpResponseHeader header;
      header.setDate();
      header.setVersion("HTTP/1.1");
      header.setStatus(404, "Not Found");
      header.setField("host", "localhost:80");
      header.setField("Content-Type", "text/html");
      header.setField("Connection", "close");

      string date;
      string expect;
      expect.append("HTTP/1.1 404 Not Found\r\n");
      expect.append("Connection: close\r\n");
      expect.append("Content-Type: text/html\r\n");
      expect.append("Date: ");
      header.getField("Date", date);
      expect.append(date);
      expect.append("\r\n");
      expect.append("Host: localhost:80\r\n");
      expect.append("\r\n");

      string str = header.toString();
      assertStrCmp(str.c_str(), expect.c_str());

      HttpResponseHeader header2;
      header2.parse(str);

      string str2 = header2.toString();
      assertStrCmp(str2.c_str(), expect.c_str());
   }
   tr.passIfNoException();

   tr.test("Multiple fields with same name");
   {
      HttpResponseHeader header;
      header.setDate();
      header.setVersion("HTTP/1.1");
      header.setStatus(404, "Not Found");
      header.setField("host", "localhost:80");
      header.setField("Content-Type", "text/html");
      header.setField("Connection", "close");
      header.addField("Set-Cookie", "cookie1=value1; max-age=0; path=/");
      header.addField("Set-Cookie", "cookie2=value2; max-age=0; path=/");
      header.addField("Set-Cookie", "cookie3=value3; max-age=0; path=/");

      string date;
      string expect;
      expect.append("HTTP/1.1 404 Not Found\r\n");
      expect.append("Connection: close\r\n");
      expect.append("Content-Type: text/html\r\n");
      expect.append("Date: ");
      header.getField("Date", date);
      expect.append(date);
      expect.append("\r\n");
      expect.append("Host: localhost:80\r\n");
      expect.append("Set-Cookie: cookie1=value1; max-age=0; path=/\r\n");
      expect.append("Set-Cookie: cookie2=value2; max-age=0; path=/\r\n");
      expect.append("Set-Cookie: cookie3=value3; max-age=0; path=/\r\n");
      expect.append("\r\n");

      string str = header.toString();
      assertStrCmp(str.c_str(), expect.c_str());

      HttpResponseHeader header2;
      header2.parse(str);

      string str2 = header2.toString();
      assertStrCmp(str2.c_str(), expect.c_str());
   }
   tr.passIfNoException();

   tr.test("hasContentType");
   {
      HttpResponseHeader header;

      header.clearFields();
      header.setField("Content-Type", "text/html");
      assert(header.hasContentType("text/html"));

      header.clearFields();
      header.setField("Content-Type", "text/html; params");
      assert(header.hasContentType("text/html"));

      header.clearFields();
      header.setField("Content-Type", "text/html; params");
      assert(!header.hasContentType("text/plain"));
   }
   tr.passIfNoException();

   tr.ungroup();
}
示例#6
0
bool SampleService::sendm3u(BtpAction* action, DynamicObject& fileInfos)
{
   bool rval = true;

   // build m3u file
   string content;
   content.append("#EXTM3U\n");

   // create play list
   char temp[22];
   FileInfoIterator i = fileInfos.getIterator();
   while(i->hasNext())
   {
      FileInfo& fi = i->next();
      Media& media = fi["media"];
      int sampleLength =
         media["sampleRange"][1]->getUInt32() -
         media["sampleRange"][0]->getUInt32();
      snprintf(temp, 22, "%u", (sampleLength < 0 ? 0 : sampleLength));

      string artist;
      if(media["contributors"]->hasMember("Performer"))
      {
         artist = media["contributors"]["Performer"][0]["name"]->getString();
      }
      else if(media["contributors"]->hasMember("Artist"))
      {
         artist = media["contributors"]["Artist"][0]["name"]->getString();
      }

      content.append("#EXTINF:");
      content.append(temp);
      content.push_back(',');
      content.append(artist);
      content.append(" - ");
      content.append(media["title"]->getString());
      content.push_back('\n');

      // FIXME: get host from configuration or something
      // needs to be public IP that remote side can access
      DynamicObject vars;
      action->getResourceQuery(vars);
      if(!vars->hasMember("nodeuser"))
      {
         BM_ID_SET(vars["nodeuser"], mNode->getDefaultUserId());
      }

      HttpRequestHeader* header = action->getRequest()->getHeader();
      string host = header->getFieldValue("X-Forwarded-Host");
      if(host.length() == 0)
      {
         host = header->getFieldValue("Host");
      }
      content.append("http://");
      content.append(host);
      content.append("/api/3.0/sales/samples/file/");
      content.append(fi["mediaId"]->getString());
      content.push_back('/');
      content.append(fi["id"]->getString());
      content.push_back('\n');
   }

   // set up response header
   HttpResponseHeader* header = action->getResponse()->getHeader();
   header->setField("Content-Type", "audio/x-mpegurl");
   header->setField(
      "Content-Disposition", "attachment; filename=bitmunk-sample.m3u");

   // create content input stream
   ByteBuffer b(content.length());
   b.put(content.c_str(), content.length(), false);
   ByteArrayInputStream bais(&b);

   // send sample
   action->getResponse()->getHeader()->setStatus(200, "OK");
   action->sendResult(&bais);

   return rval;
}
void ProxyResourceHandler::operator()(BtpAction* action)
{
   // get request host
   HttpRequestHeader* hrh = action->getRequest()->getHeader();
   string host = hrh->getFieldValue("X-Forwarded-Host");
   if(host.length() == 0)
   {
      host = hrh->getFieldValue("Host");
   }

   // find a rule
   Rule* rule = findRule(action, host);
   if(rule == NULL)
   {
      // delegate to rest resource handler
      RestResourceHandler::operator()(action);
   }
   else
   {
      // get URL to proxy or redirect to
      UrlRef url = rule->url;

      // get url host
      string urlHost;
      HttpResponse* res = action->getResponse();
      bool secure = res->getConnection()->isSecure();

      // if URL has no host, reuse incoming host
      if(url->getHost().length() == 0)
      {
         urlHost = host;
      }
      // if URL has no port or uses a default port number, only use URL host
      else if(
         (url->getPort() == 0) ||
         (secure && url->getPort() == 443) ||
         (!secure && url->getPort() == 80))
      {
         urlHost = url->getHost();
      }
      // use URL host and port
      else
      {
         urlHost = url->getHostAndPort();
      }

      // handle 0.0.0.0 (any host) by replacing it with the request host
      if(strncmp(urlHost.c_str(), "0.0.0.0", 8) == 0)
      {
         // 0.0.0.0 is 8 chars long
         urlHost.replace(0, 8, host.substr(0, host.find(':')).c_str());
      }

      // rewrite the request path if it does not match URL path
      string path = hrh->getPath();
      if(strcmp(path.c_str(), url->getPath().c_str()) != 0)
      {
         // check for path wildcard
         if(strcmp(rule->path, "*") == 0)
         {
            // since a wildcard is used, prepend the URL path to the
            // resource (if the url path isn't '/')
            string urlPath = url->getPath();
            if(urlPath.length() > 1)
            {
               path.insert(0, url->getPath().c_str());
            }
         }
         else
         {
            // replace the part of the resource that matched the proxy
            // rule with the rewrite path from the proxy URL
            path.replace(0, strlen(rule->path), url->getPath().c_str());
         }
      }

      // do redirect if appropriate
      if(rule->type == Rule::Redirect)
      {
         // set response code
         HttpResponseHeader* header = res->getHeader();
         if(rule->permanent)
         {
            header->setStatus(301, "Moved Permanently");
         }
         else
         {
            header->setStatus(302, "Found");
         }

         // build new location url
         bool secure = res->getConnection()->isSecure();
         header->setField("Location", StringTools::format("%s://%s%s",
            secure ? "https" : "http", urlHost.c_str(), path.c_str()));
         action->sendResult();
      }
      // do proxy
      else if(rule->type == Rule::Proxy)
      {
         // get client-side request
         HttpRequest* req = action->getRequest();

         // do path rewrite
         hrh->setPath(path.c_str());

         // add X-Forwarded headers
         hrh->appendFieldValue("X-Forwarded-For",
            req->getConnection()->getRemoteAddress()->toString(true).c_str());
         hrh->appendFieldValue("X-Forwarded-Host",
            hrh->getFieldValue("Host").c_str());
         hrh->appendFieldValue("X-Forwarded-Server",
            SocketTools::getHostname().c_str());

         // rewrite host if rule specifies it
         if(rule->rewriteHost)
         {
            hrh->setField("Host", urlHost.c_str());
         }

         // do proxy:
         MO_CAT_INFO(BM_NODE_CAT,
            "ProxyResourceHandler proxying %s%s => %s%s",
            host.c_str(), hrh->getPath(), urlHost.c_str(), path.c_str());
         MO_CAT_DEBUG(BM_NODE_CAT,
            "ProxyResourceHandler request header for %s%s => %s%s:\n%s",
            host.c_str(), hrh->getPath(),
            urlHost.c_str(), path.c_str(),
            hrh->toString().c_str());

         // get a connection
         BtpClient* btpc = mNode->getMessenger()->getBtpClient();
         HttpConnection* conn = btpc->createConnection(false, &(*url));
         if(conn == NULL)
         {
            // send service unavailable
            HttpResponseHeader* header = action->getResponse()->getHeader();
            header->setStatus(503, "Service Unavailable");
            string content =
               "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
               "<html><head>\n"
               "<title>503 Service Unavailable</title>\n"
               "</head><body>\n"
               "<h1>Service Unavailable</h1>\n"
               "<p>The service was not available.</p>\n"
               "</body></html>";
            ByteBuffer b(content.length());
            b.put(content.c_str(), content.length(), false);
            ByteArrayInputStream bais(&b);
            action->sendResult(&bais);
         }
         else
         {
            // proxy the client's request and receive server's header (by
            // writing it into the client's response header)
            HttpResponse* res = action->getResponse();
            if(_proxyHttp(req->getHeader(), req->getConnection(), conn) &&
               conn->receiveHeader(res->getHeader()))
            {
               // proxy the server's response, consider result sent
               _proxyHttp(res->getHeader(), conn, req->getConnection());
               action->setResultSent(true);
            }

            // close connection
            conn->close();

            // clean up
            delete conn;
         }

         if(!action->isResultSent())
         {
            // send exception (client's fault if code < 500)
            ExceptionRef e = Exception::get();
            action->sendException(e, e->getCode() < 500);
         }
      }
   }
}
void HttpConnectionServicer::serviceConnection(Connection* c)
{
   // wrap connection, set default timeouts to 30 seconds
   HttpConnection hc(c, false);
   hc.setReadTimeout(30000);
   hc.setWriteTimeout(30000);

   // monitor connection
   if(!mConnectionMonitor.isNull())
   {
      mConnectionMonitor->beforeServicingConnection(&hc);
   }

   // create request
   HttpRequest* request = hc.createRequest();
   HttpRequestHeader* reqHeader = request->getHeader();

   // create response
   HttpResponse* response = request->createResponse();
   HttpResponseHeader* resHeader = response->getHeader();

   // handle keep-alive (HTTP/1.1 keep-alive is on by default)
   bool keepAlive = true;
   bool noerror = true;
   while(keepAlive && noerror)
   {
      // set defaults
      resHeader->setVersion("HTTP/1.1");
      resHeader->setDate();
      resHeader->setField("Server", mServerName);

      // monitor request waiting
      if(!mConnectionMonitor.isNull())
      {
         mConnectionMonitor->beforeRequest(&hc);
      }

      // receive request header
      if((noerror = request->receiveHeader()))
      {
         // begin new request state
         hc.getRequestState()->beginRequest();

         // monitor received request
         if(!mConnectionMonitor.isNull())
         {
            mConnectionMonitor->beforeServicingRequest(
               &hc, request, response);
         }

         // do request modification
         if(mRequestModifier != NULL)
         {
            mRequestModifier->modifyRequest(request);
         }

         // check http version
         bool version10 = (strcmp(reqHeader->getVersion(), "HTTP/1.0") == 0);
         bool version11 = (strcmp(reqHeader->getVersion(), "HTTP/1.1") == 0);

         // only version 1.0 and 1.1 supported
         if(version10 || version11)
         {
            // set response version according to request version
            resHeader->setVersion(reqHeader->getVersion());

            // use proxy'd host field if one was used
            // else use host field if one was used
            string host;
            if(reqHeader->getField("X-Forwarded-Host", host) ||
               reqHeader->getField("Host", host))
            {
               resHeader->setField("Host", host);
            }

            // get connection header
            string connHeader;
            if(reqHeader->getField("Connection", connHeader))
            {
               if(strcasecmp(connHeader.c_str(), "close") == 0)
               {
                  keepAlive = false;
               }
               else if(strcasecmp(connHeader.c_str(), "keep-alive") == 0)
               {
                  keepAlive = true;
               }
            }
            else if(version10)
            {
               // if HTTP/1.0 and no keep-alive header, keep-alive is off
               keepAlive = false;
            }

            // get request path and normalize it
            const char* inPath = reqHeader->getPath();
            char outPath[strlen(inPath) + 2];
            HttpRequestServicer::normalizePath(inPath, outPath);

            // find appropriate request servicer for path
            HttpRequestServicer* hrs = NULL;

            // find secure/non-secure servicer
            hrs = findRequestServicer(host, outPath, hc.isSecure());
            if(hrs != NULL)
            {
               // service request
               hrs->serviceRequest(request, response);

               // turn off keep-alive if response has close connection field
               if(keepAlive)
               {
                  if(resHeader->getField("Connection", connHeader) &&
                     strcasecmp(connHeader.c_str(), "close") == 0)
                  {
                     keepAlive = false;
                  }
               }

               // if servicer closed connection, turn off keep-alive
               if(keepAlive && c->isClosed())
               {
                  keepAlive = false;
               }
            }
            else
            {
               // no servicer, so send 404 Not Found
               const char* html =
                  "<html><body><h2>404 Not Found</h2></body></html>";
               resHeader->setStatus(404, "Not Found");
               resHeader->setField("Content-Type", "text/html");
               resHeader->setField("Content-Length", 48);
               resHeader->setField("Connection", "close");
               if((noerror = response->sendHeader()))
               {
                  ByteArrayInputStream is(html, 48);
                  noerror = response->sendBody(&is);
               }
            }
         }
         else
         {
            // send 505 HTTP Version Not Supported
            const char* html =
               "<html><body>"
               "<h2>505 HTTP Version Not Supported</h2>"
               "</body></html>";
            resHeader->setStatus(505, "HTTP Version Not Supported");
            resHeader->setField("Content-Type", "text/html");
            resHeader->setField("Content-Length", 65);
            resHeader->setField("Connection", "close");
            if((noerror = response->sendHeader()))
            {
               ByteArrayInputStream is(html, 65);
               noerror = response->sendBody(&is);
            }
         }

         // monitor serviced request
         if(!mConnectionMonitor.isNull())
         {
            mConnectionMonitor->afterServicingRequest(
               &hc, request, response);
         }
      }
      else
      {
         // begin new request state
         hc.getRequestState()->beginRequest();

         // monitor request error
         if(!mConnectionMonitor.isNull())
         {
            mConnectionMonitor->beforeRequestError(
               &hc, request, response);
         }

         // exception occurred while receiving header
         ExceptionRef e = Exception::get();
         // if no header then drop through and close connection
         if(e->isType("monarch.http.NoHeader"))
         {
            keepAlive = false;
         }
         // for bad header or request set 400
         else if(e->isType("monarch.http.BadHeader") ||
            e->isType("monarch.http.BadRequest"))
         {
            // send 400 Bad Request
            const char* html =
               "<html><body><h2>400 Bad Request</h2></body></html>";
            response->getHeader()->setStatus(400, "Bad Request");
            response->getHeader()->setField("Content-Type", "text/html");
            response->getHeader()->setField("Content-Length", 50);
            response->getHeader()->setField("Connection", "close");
            if(response->sendHeader())
            {
               ByteArrayInputStream is(html, 50);
               response->sendBody(&is);
            }
         }
         // if the exception was an interruption, then send a 503
         else if(e->isType("monarch.io.InterruptedException") ||
                 e->isType("monarch.rt.Interrupted"))
         {
            // send 503 Service Unavailable
            const char* html =
               "<html><body><h2>503 Service Unavailable</h2></body></html>";
            resHeader->setStatus(503, "Service Unavailable");
            resHeader->setField("Content-Type", "text/html");
            resHeader->setField("Content-Length", 58);
            resHeader->setField("Connection", "close");
            if((noerror = response->sendHeader()))
            {
               ByteArrayInputStream is(html, 58);
               noerror = response->sendBody(&is);
            }
         }
         // if the exception was not a socket error then send an internal
         // server error response
         else if(!e->isType("monarch.net.Socket", true))
         {
            // send 500 Internal Server Error
            const char* html =
               "<html><body><h2>500 Internal Server Error</h2></body></html>";
            resHeader->setStatus(500, "Internal Server Error");
            resHeader->setField("Content-Type", "text/html");
            resHeader->setField("Content-Length", 60);
            resHeader->setField("Connection", "close");
            if((noerror = response->sendHeader()))
            {
               ByteArrayInputStream is(html, 60);
               noerror = response->sendBody(&is);
            }
         }
         else
         {
            // log socket error
            if(e->getDetails()->hasMember("error"))
            {
               // build error string
               string error;
               DynamicObjectIterator i =
                  e->getDetails()["error"].getIterator();
               while(i->hasNext())
               {
                  error.append(i->next()->getString());
                  if(i->hasNext())
                  {
                     error.push_back(',');
                  }
               }
               MO_CAT_ERROR(MO_HTTP_CAT,
                  "Connection error: ['%s','%s','%s']",
                  e->getMessage(), e->getType(), error.c_str());
            }
            else
            {
               MO_CAT_ERROR(MO_HTTP_CAT,
                  "Connection error: ['%s','%s']",
                  e->getMessage(), e->getType());
            }
         }

         // monitor request error
         if(!mConnectionMonitor.isNull())
         {
            mConnectionMonitor->afterRequestError(
               &hc, request, response, e);
         }
      }

      // monitor request
      if(!mConnectionMonitor.isNull())
      {
         mConnectionMonitor->afterRequest(&hc);
      }

      if(keepAlive && noerror)
      {
         // set keep-alive timeout (defaults to 5 minutes)
         hc.setReadTimeout(1000 * 60 * 5);

         // clear request and response header fields
         reqHeader->clearFields();
         resHeader->clearFields();
         resHeader->clearStatus();
      }
   }

   // clean up request and response
   delete request;
   delete response;

   // monitor connection
   if(!mConnectionMonitor.isNull())
   {
      mConnectionMonitor->afterServicingConnection(&hc);
   }

   // close connection
   hc.close();
}
示例#9
0
BOOL CWebSocketProtocol::HandShake(HttpRequestHeader &header, CConnectionSession<CWebSocketProtocol> &pConn)
{
	if (header.GetField("Sec-WebSocket-Key").size() > 0 && header.GetField("Sec-WebSocket-Version") == "13")
	{
		//V76协议
		std::string RawKey = header.GetField("Sec-WebSocket-Key") + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
		//获取Sec-WebSocket-Key然后加上固定字符串组合成新的Key

		//新Key  SHA1后再BASE64编码成的字符串成为Sec-WebSocket-Accept的值返回给客户端
		BYTE DigestKey[20];
		CSHA1 sha1;
		CBase64 base64;
		sha1.Input((CHAR *)RawKey.c_str(), RawKey.size());
		sha1.Result(DigestKey);
		
		std::string str = base64.Encode(DigestKey, 20);

		std::string strResponse("HTTP/1.1 101 Switching Protocols\r\n");
		strResponse += "Upgrade: websocket\r\n";
		strResponse += "Connection: Upgrade\r\n";
		strResponse += "Sec-WebSocket-Accept: " + str + "\r\n";
		strResponse += "WebSocket-Origin: " + header.GetOrigin() + "\r\n";
		strResponse += "WebSocket-Location: ws://";
		strResponse += header.GetHost() + header.GetPath() + "\r\n\r\n";
		
		pConn.WritePacket((BYTE *)strResponse.c_str(), strResponse.size());
		mWebsocketVersion = 76;
		mIshandShaked = TRUE;
		mRemainLength = 0;
		ZeroMemory(mDataBuffer, MAX_PACKET_BUFFER_LENGTH);
		GetPacket = &CWebSocketProtocol::GetPacket76;
		WritePacket = &CWebSocketProtocol::WritePacket76;
		return TRUE;

	}
	else if (header.GetField("Sec-WebSocket-Key1").size() > 0)
	{
		//如果是V75协议,头后面还跟着8字节的内容
		if (header.ContentSize() == 8)
		{
			DWORD Space1Num = 0;
			DWORD Space2Num = 0;
			DWORD Key1Length;
			DWORD Key2Length;
			BYTE Digits1[20], Digits2[20];
			DWORD Index = 0;
			DWORD Result1, Result2;

			const char *szkey1 = header.GetField("Sec-WebSocket-Key1").c_str();
			const char *szKey2 = header.GetField("Sec-WebSocket-Key2").c_str();
			Key1Length = strlen(szkey1);
			Key2Length = strlen(szKey2);

			//数空格,获取数字
			for (DWORD i = 0; i<Key1Length; i++)
			{
				if (szkey1[i] == ' ') Space1Num++;
				else if (szkey1[i] >= '0' && szkey1[i] <= '9')
				{
					Digits1[Index++] = szkey1[i];
				}
			}

			Index = 0;
			for (DWORD i = 0; i<Key2Length; i++)
			{
				if (szKey2[i] == ' ') Space2Num++;
				else if (szKey2[i] >= '0' && szKey2[i] <= '9')
				{
					Digits2[Index++] = szKey2[i];
				}
			}

			//根据Key1, Key2获取两个无符号正整数,Big Endian
			Result1 = htonl((DWORD)((strtoul((const char *)Digits1, NULL, 10)) / Space1Num));
			Result2 = htonl((DWORD)((strtoul((const char *)Digits2, NULL, 10)) / Space2Num));

			//把两个整数与最后的8个字节合并成16字节数组
			BYTE ResultKey[16];
			CopyMemory(ResultKey, &Result1, sizeof(DWORD));
			CopyMemory(ResultKey + sizeof(DWORD), &Result2, sizeof(DWORD));
			CopyMemory(ResultKey + sizeof(DWORD) * 2, header.Content(), 8);


			std::string strResponse("HTTP/1.1 101 Web Socket Protocol Handshake\r\n");
			strResponse += "Upgrade: WebSocket\r\n";
			strResponse += "Connection: Upgrade\r\n";
			strResponse += "Sec-WebSocket-Origin: ";
			strResponse += header.GetOrigin() + "\r\n";
			strResponse += "Sec-WebSocket-Location: ws://";
			strResponse += header.GetHost() + header.GetPath() + "\r\n\r\n";

			//Md5得到的16字节 发送出去
			CMD5 md5(ResultKey, 16);
			BYTE *md5Key = (BYTE *)md5.Digest();

			BYTE Response[200];
			DWORD ResponseHeaderLength = strResponse.size();
			CopyMemory(Response, strResponse.c_str(), ResponseHeaderLength);
			CopyMemory(Response + ResponseHeaderLength, md5Key, 16);
			pConn.WritePacket(Response, ResponseHeaderLength+16);
			Response[ResponseHeaderLength+16] = '\0';
		
			GetPacket = &CWebSocketProtocol::GetPacket75;
			WritePacket = &CWebSocketProtocol::WritePacket75;
			ZeroMemory(mDataBuffer, MAX_PACKET_BUFFER_LENGTH);
			mRemainLength = 0;
			mIshandShaked = TRUE;
			return TRUE;
		}
	}
	else 
	{
		//其他情况未实现的协议,不处理
		mRemainLength = 0;
		return FALSE;
	}
	
	return FALSE;
}