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(); } }
/* 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; }
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; }
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(); }
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(); }
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; }