mirror of
https://github.com/drogonframework/drogon.git
synced 2025-08-20 00:02:24 -04:00
add HttpServer class
This commit is contained in:
parent
81ef7d0392
commit
3641a3edef
2
.gitignore
vendored
2
.gitignore
vendored
@ -32,3 +32,5 @@
|
||||
*.app
|
||||
|
||||
build
|
||||
cmake-build-debug
|
||||
.idea
|
||||
|
6
CMakeLists.txt
Normal file → Executable file
6
CMakeLists.txt
Normal file → Executable file
@ -2,6 +2,8 @@ cmake_minimum_required (VERSION 2.6)
|
||||
|
||||
project (DROGON C CXX)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -g -ggdb")
|
||||
|
||||
#EXEC_PROGRAM (gcc ARGS "--version | grep '^gcc'|awk '{print $3}' | sed s'/)//g'" OUTPUT_VARIABLE version)
|
||||
#MESSAGE(STATUS "This is gcc version:: " ${version})
|
||||
|
||||
@ -17,7 +19,7 @@ add_subdirectory(trantor)
|
||||
SET(CMAKE_INSTALL_PREFIX /usr/local/drogon)
|
||||
#INSTALL(FILES trantor.cfg DESTINATION conf)
|
||||
|
||||
#include_directories(${PROJECT_SOURCE_DIR}/src/base/codec ${PROJECT_SOURCE_DIR}/src/Terminus ${CMAKE_BINARY_DIR}/src/base/protobuf_message)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/trantor ${PROJECT_SOURCE_DIR}/drogon/inc)
|
||||
|
||||
aux_source_directory(${PROJECT_SOURCE_DIR}/drogon/src DIR_SRCS)
|
||||
|
||||
@ -33,6 +35,6 @@ add_dependencies(drogon trantor)
|
||||
# set (LIBCONFIG libconfig++)
|
||||
#endif()
|
||||
|
||||
target_link_libraries(drogon trantor)
|
||||
target_link_libraries(drogon trantor pthread)
|
||||
#crypt dl m pqxx pq hiredis mongocxx bsoncxx jsoncpp ${LIBCONFIG})
|
||||
INSTALL(TARGETS drogon DESTINATION bin)
|
||||
|
298
drogon/inc/HttpRequest.h
Executable file
298
drogon/inc/HttpRequest.h
Executable file
@ -0,0 +1,298 @@
|
||||
// Copyright 2010, Shuo Chen. All rights reserved.
|
||||
// http://code.google.com/p/muduo/
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the License file.
|
||||
|
||||
// Author: Shuo Chen (chenshuo at chenshuo dot com)
|
||||
//
|
||||
// This is a public header file, it must only include public header files.
|
||||
|
||||
//taken from muduo and modified
|
||||
//
|
||||
// Copyright 2018, An Tao. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a MIT license
|
||||
// that can be found in the License file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <trantor/utils/MsgBuffer.h>
|
||||
|
||||
#include <map>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
using std::string;
|
||||
using namespace trantor;
|
||||
|
||||
class HttpRequest
|
||||
{
|
||||
public:
|
||||
friend class HttpContext;
|
||||
enum Method {
|
||||
kInvalid, kGet, kPost, kHead, kPut, kDelete
|
||||
};
|
||||
enum Version {
|
||||
kUnknown, kHttp10, kHttp11
|
||||
};
|
||||
|
||||
HttpRequest()
|
||||
: method_(kInvalid),
|
||||
version_(kUnknown)
|
||||
{
|
||||
}
|
||||
|
||||
void setVersion(Version v)
|
||||
{
|
||||
version_ = v;
|
||||
}
|
||||
|
||||
Version getVersion() const
|
||||
{
|
||||
return version_;
|
||||
}
|
||||
void parsePremeter();
|
||||
bool setMethod(const char* start, const char* end)
|
||||
{
|
||||
|
||||
assert(method_ == kInvalid);
|
||||
std::string m(start, end);
|
||||
if (m == "GET") {
|
||||
method_ = kGet;
|
||||
} else if (m == "POST") {
|
||||
method_ = kPost;
|
||||
} else if (m == "HEAD") {
|
||||
method_ = kHead;
|
||||
} else if (m == "PUT") {
|
||||
method_ = kPut;
|
||||
} else if (m == "DELETE") {
|
||||
method_ = kDelete;
|
||||
} else {
|
||||
method_ = kInvalid;
|
||||
}
|
||||
if(method_!=kInvalid)
|
||||
{
|
||||
content_="";
|
||||
query_="";
|
||||
cookies_.clear();
|
||||
premeter_.clear();
|
||||
headers_.clear();
|
||||
}
|
||||
return method_ != kInvalid;
|
||||
}
|
||||
|
||||
bool setMethod(const Method method)
|
||||
{
|
||||
method_ = method;
|
||||
content_="";
|
||||
query_="";
|
||||
cookies_.clear();
|
||||
premeter_.clear();
|
||||
headers_.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
Method method() const
|
||||
{
|
||||
return method_;
|
||||
}
|
||||
|
||||
const char* methodString() const
|
||||
{
|
||||
const char* result = "UNKNOWN";
|
||||
switch(method_) {
|
||||
case kGet:
|
||||
result = "GET";
|
||||
break;
|
||||
case kPost:
|
||||
result = "POST";
|
||||
break;
|
||||
case kHead:
|
||||
result = "HEAD";
|
||||
break;
|
||||
case kPut:
|
||||
result = "PUT";
|
||||
break;
|
||||
case kDelete:
|
||||
result = "DELETE";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void setPath(const char* start, const char* end)
|
||||
{
|
||||
path_.assign(start, end);
|
||||
}
|
||||
void setPath(const std::string& path)
|
||||
{
|
||||
path_ = path;
|
||||
}
|
||||
|
||||
std::map<std::string,std::string > getPremeter() const
|
||||
{
|
||||
return premeter_;
|
||||
}
|
||||
const std::string& path() const
|
||||
{
|
||||
return path_;
|
||||
}
|
||||
|
||||
void setQuery(const char* start, const char* end)
|
||||
{
|
||||
query_.assign(start, end);
|
||||
}
|
||||
void setQuery(const std::string& query)
|
||||
{
|
||||
query_ = query;
|
||||
}
|
||||
// const string& content() const
|
||||
// {
|
||||
// return content_;
|
||||
// }
|
||||
const std::string& query() const
|
||||
{
|
||||
if(query_!="")
|
||||
return query_;
|
||||
if(method_==kPost)
|
||||
return content_;
|
||||
return query_;
|
||||
}
|
||||
|
||||
// void setReceiveTime(Timestamp t)
|
||||
// {
|
||||
// receiveTime_ = t;
|
||||
// }
|
||||
//
|
||||
// Timestamp receiveTime() const
|
||||
// {
|
||||
// return receiveTime_;
|
||||
// }
|
||||
|
||||
void addHeader(const char* start, const char* colon, const char* end)
|
||||
{
|
||||
std::string field(start, colon);
|
||||
++colon;
|
||||
while (colon < end && isspace(*colon)) {
|
||||
++colon;
|
||||
}
|
||||
std::string value(colon, end);
|
||||
while (!value.empty() && isspace(value[value.size() - 1])) {
|
||||
value.resize(value.size() - 1);
|
||||
}
|
||||
headers_[field] = value;
|
||||
transform(field.begin(), field.end(), field.begin(), ::tolower);
|
||||
if(field == "cookie") {
|
||||
LOG_INFO<<"cookies!!!:"<<value;
|
||||
std::string::size_type pos;
|
||||
while((pos = value.find(";")) != std::string::npos) {
|
||||
std::string coo = value.substr(0, pos);
|
||||
auto epos = coo.find("=");
|
||||
if(epos != std::string::npos) {
|
||||
std::string cookie_name = coo.substr(0, epos);
|
||||
std::string::size_type cpos=0;
|
||||
while(isspace(cookie_name[cpos])&&cpos<cookie_name.length())
|
||||
cpos++;
|
||||
cookie_name=cookie_name.substr(cpos);
|
||||
std::string cookie_value = coo.substr(epos + 1);
|
||||
cookies_[cookie_name] = cookie_value;
|
||||
}
|
||||
value=value.substr(pos+1);
|
||||
}
|
||||
if(value.length()>0)
|
||||
{
|
||||
std::string &coo = value;
|
||||
auto epos = coo.find("=");
|
||||
if(epos != std::string::npos) {
|
||||
std::string cookie_name = coo.substr(0, epos);
|
||||
std::string::size_type cpos=0;
|
||||
while(isspace(cookie_name[cpos])&&cpos<cookie_name.length())
|
||||
cpos++;
|
||||
cookie_name=cookie_name.substr(cpos);
|
||||
std::string cookie_value = coo.substr(epos + 1);
|
||||
cookies_[cookie_name] = cookie_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string getHeader(const std::string& field) const
|
||||
{
|
||||
std::string result;
|
||||
std::map<std::string, std::string>::const_iterator it = headers_.find(field);
|
||||
if (it != headers_.end()) {
|
||||
result = it->second;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string getCookie(const std::string& field) const
|
||||
{
|
||||
std::string result;
|
||||
std::map<std::string, std::string>::const_iterator it = cookies_.find(field);
|
||||
if (it != cookies_.end()) {
|
||||
result = it->second;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const std::map<std::string, std::string>& headers() const
|
||||
{
|
||||
return headers_;
|
||||
}
|
||||
|
||||
const std::map<std::string, std::string>& cookies() const
|
||||
{
|
||||
return cookies_;
|
||||
}
|
||||
|
||||
const std::string& getContent() const
|
||||
{
|
||||
return content_;
|
||||
}
|
||||
void swap(HttpRequest& that)
|
||||
{
|
||||
std::swap(method_, that.method_);
|
||||
path_.swap(that.path_);
|
||||
query_.swap(that.query_);
|
||||
//receiveTime_.swap(that.receiveTime_);
|
||||
headers_.swap(that.headers_);
|
||||
}
|
||||
|
||||
void setContent(const std::string& content)
|
||||
{
|
||||
content_ = content;
|
||||
}
|
||||
void addHeader(const std::string& key, const std::string& value)
|
||||
{
|
||||
headers_[key] = value;
|
||||
}
|
||||
void addCookie(const std::string& key, const std::string& value)
|
||||
{
|
||||
cookies_[key] = value;
|
||||
}
|
||||
|
||||
void appendToBuffer(MsgBuffer* output) const;
|
||||
private:
|
||||
Method method_;
|
||||
Version version_;
|
||||
std::string path_;
|
||||
std::string query_;
|
||||
|
||||
//trantor::Date receiveTime_;
|
||||
std::map<std::string, std::string> headers_;
|
||||
std::map<std::string, std::string> cookies_;
|
||||
std::map<std::string, std::string> premeter_;
|
||||
protected:
|
||||
std::string content_;
|
||||
size_t contentLen;
|
||||
|
||||
};
|
||||
|
||||
|
246
drogon/inc/HttpResponse.h
Executable file
246
drogon/inc/HttpResponse.h
Executable file
@ -0,0 +1,246 @@
|
||||
// Copyright 2010, Shuo Chen. All rights reserved.
|
||||
// http://code.google.com/p/muduo/
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the License file.
|
||||
|
||||
// Author: Shuo Chen (chenshuo at chenshuo dot com)
|
||||
//
|
||||
// This is a public header file, it must only include public header files.
|
||||
|
||||
|
||||
//taken from muduo and modified
|
||||
//
|
||||
// Copyright 2018, An Tao. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a MIT license
|
||||
// that can be found in the License file.
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <trantor/utils/MsgBuffer.h>
|
||||
#include <map>
|
||||
|
||||
#include <string>
|
||||
using std::string;
|
||||
#define CT_APPLICATION_JSON 1
|
||||
#define CT_TEXT_PLAIN 2
|
||||
#define CT_TEXT_HTML 3
|
||||
#define CT_APPLICATION_X_JAVASCRIPT 4
|
||||
#define CT_TEXT_CSS 5
|
||||
#define CT_TEXT_XML 6
|
||||
#define CT_APPLICATION_XML 7
|
||||
#define CT_TEXT_XSL 8
|
||||
#define CT_APPLICATION_OCTET_STREAM 9
|
||||
#define CT_APPLICATION_X_FONT_TRUETYPE 10
|
||||
#define CT_APPLICATION_X_FONT_OPENTYPE 11
|
||||
#define CT_APPLICATION_FONT_WOFF 12
|
||||
#define CT_APPLICATION_FONT_WOFF2 13
|
||||
#define CT_APPLICATION_VND_MS_FONTOBJ 14
|
||||
#define CT_IMAGE_SVG_XML 15
|
||||
#define CT_IMAGE_PNG 16
|
||||
#define CT_IMAGE_JPG 17
|
||||
#define CT_IMAGE_GIF 18
|
||||
#define CT_IMAGE_XICON 19
|
||||
#define CT_IMAGE_ICNS 20
|
||||
#define CT_IMAGE_BMP 21
|
||||
using namespace trantor;
|
||||
class HttpResponse
|
||||
{
|
||||
friend class HttpContext;
|
||||
public:
|
||||
enum HttpStatusCode {
|
||||
kUnknown,
|
||||
k200Ok = 200,
|
||||
k301MovedPermanently = 301,
|
||||
k302Found = 302,
|
||||
k304NotModified = 304,
|
||||
k400BadRequest = 400,
|
||||
k404NotFound = 404,
|
||||
};
|
||||
|
||||
enum Version {
|
||||
kHttp10, kHttp11
|
||||
};
|
||||
|
||||
explicit HttpResponse(bool close)
|
||||
: statusCode_(kUnknown),
|
||||
closeConnection_(close),
|
||||
left_body_length_(0),
|
||||
current_chunk_length_(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit HttpResponse()
|
||||
: statusCode_(kUnknown),
|
||||
closeConnection_(false),
|
||||
left_body_length_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void setStatusCode(HttpStatusCode code)
|
||||
{
|
||||
statusCode_ = code;
|
||||
setStatusMessage(web_response_code_to_string(code));
|
||||
}
|
||||
|
||||
void setStatusCode(HttpStatusCode code, const std::string& status_message)
|
||||
{
|
||||
statusCode_ = code;
|
||||
setStatusMessage(status_message);
|
||||
}
|
||||
|
||||
void setVersion(const Version v)
|
||||
{
|
||||
v_ = v;
|
||||
}
|
||||
|
||||
|
||||
void setCloseConnection(bool on)
|
||||
{
|
||||
closeConnection_ = on;
|
||||
}
|
||||
|
||||
bool closeConnection() const
|
||||
{
|
||||
return closeConnection_;
|
||||
}
|
||||
|
||||
void setContentTypeCode(uint8_t type)
|
||||
{
|
||||
contentType_=type;
|
||||
setContentType(web_content_type_to_string(type));
|
||||
}
|
||||
|
||||
|
||||
std::string getHeader(const std::string& key)
|
||||
{
|
||||
if(headers_.find(key) == headers_.end())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return headers_[key];
|
||||
}
|
||||
}
|
||||
void addHeader(const std::string& key, const std::string& value)
|
||||
{
|
||||
headers_[key] = value;
|
||||
}
|
||||
|
||||
void addHeader(const char* start, const char* colon, const char* end)
|
||||
{
|
||||
std::string field(start, colon);
|
||||
++colon;
|
||||
while (colon < end && isspace(*colon)) {
|
||||
++colon;
|
||||
}
|
||||
std::string value(colon, end);
|
||||
while (!value.empty() && isspace(value[value.size() - 1])) {
|
||||
value.resize(value.size() - 1);
|
||||
}
|
||||
headers_[field] = value;
|
||||
transform(field.begin(), field.end(), field.begin(), ::tolower);
|
||||
if(field == "cookie") {
|
||||
//LOG_INFO<<"cookies!!!:"<<value;
|
||||
std::string::size_type pos;
|
||||
while((pos = value.find(";")) != std::string::npos) {
|
||||
std::string coo = value.substr(0, pos);
|
||||
auto epos = coo.find("=");
|
||||
if(epos != std::string::npos) {
|
||||
std::string cookie_name = coo.substr(0, epos);
|
||||
std::string::size_type cpos=0;
|
||||
while(isspace(cookie_name[cpos])&&cpos<cookie_name.length())
|
||||
cpos++;
|
||||
cookie_name=cookie_name.substr(cpos);
|
||||
std::string cookie_value = coo.substr(epos + 1);
|
||||
cookies_[cookie_name] = cookie_value;
|
||||
}
|
||||
value=value.substr(pos+1);
|
||||
}
|
||||
if(value.length()>0)
|
||||
{
|
||||
std::string &coo = value;
|
||||
auto epos = coo.find("=");
|
||||
if(epos != std::string::npos) {
|
||||
std::string cookie_name = coo.substr(0, epos);
|
||||
std::string::size_type cpos=0;
|
||||
while(isspace(cookie_name[cpos])&&cpos<cookie_name.length())
|
||||
cpos++;
|
||||
cookie_name=cookie_name.substr(cpos);
|
||||
std::string cookie_value = coo.substr(epos + 1);
|
||||
cookies_[cookie_name] = cookie_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addCookie(const std::string& key, const std::string& value)
|
||||
{
|
||||
cookies_[key] = value;
|
||||
}
|
||||
void setBody(const std::string& body)
|
||||
{
|
||||
body_ = body;
|
||||
}
|
||||
void redirect(const std::string& url)
|
||||
{
|
||||
headers_["Location"] = url;
|
||||
}
|
||||
void appendToBuffer(MsgBuffer* output) const;
|
||||
|
||||
void clear()
|
||||
{
|
||||
statusCode_ = kUnknown;
|
||||
v_ = kHttp11;
|
||||
statusMessage_.clear();
|
||||
headers_.clear();
|
||||
cookies_.clear();
|
||||
body_.clear();
|
||||
left_body_length_ = 0;
|
||||
current_chunk_length_ = 0;
|
||||
}
|
||||
|
||||
// void setReceiveTime(trantor::Date t)
|
||||
// {
|
||||
// receiveTime_ = t;
|
||||
// }
|
||||
|
||||
std::string getBody() const
|
||||
{
|
||||
return body_;
|
||||
}
|
||||
|
||||
protected:
|
||||
static const std::string web_content_type_to_string(uint8_t contenttype);
|
||||
static const std::string web_response_code_to_string(int code);
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> headers_;
|
||||
std::map<std::string, std::string> cookies_;
|
||||
HttpStatusCode statusCode_;
|
||||
// FIXME: add http version
|
||||
Version v_;
|
||||
std::string statusMessage_;
|
||||
bool closeConnection_;
|
||||
std::string body_;
|
||||
size_t left_body_length_;
|
||||
size_t current_chunk_length_;
|
||||
uint8_t contentType_;
|
||||
//trantor::Date receiveTime_;
|
||||
|
||||
void setContentType(const std::string& contentType)
|
||||
{
|
||||
addHeader("Content-Type", contentType);
|
||||
}
|
||||
void setStatusMessage(const std::string& message)
|
||||
{
|
||||
statusMessage_ = message;
|
||||
}
|
||||
};
|
||||
|
||||
|
53
drogon/inc/HttpServer.h
Executable file
53
drogon/inc/HttpServer.h
Executable file
@ -0,0 +1,53 @@
|
||||
// Copyright 2018,antao. All rights reserved.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <trantor/net/TcpServer.h>
|
||||
#include <trantor/utils/NonCopyable.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
class HttpRequest;
|
||||
class HttpResponse;
|
||||
using namespace trantor;
|
||||
namespace drogon
|
||||
{
|
||||
class HttpServer : trantor::NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::function< void (const HttpRequest&,std::function<void (HttpResponse &)>)> HttpAsyncCallback;
|
||||
HttpServer(EventLoop* loop,
|
||||
const InetAddress& listenAddr,
|
||||
const std::string& name);
|
||||
|
||||
~HttpServer();
|
||||
|
||||
EventLoop* getLoop() const { return server_.getLoop(); }
|
||||
|
||||
void setHttpAsyncCallback(const HttpAsyncCallback& cb)
|
||||
{
|
||||
httpAsyncCallback_= cb;
|
||||
}
|
||||
|
||||
void setIoLoopNum(int numThreads)
|
||||
{
|
||||
server_.setIoLoopNum(numThreads);
|
||||
}
|
||||
|
||||
void start();
|
||||
|
||||
private:
|
||||
void onConnection(const TcpConnectionPtr& conn);
|
||||
void onMessage(const TcpConnectionPtr&,
|
||||
MsgBuffer*);
|
||||
void onRequest(const TcpConnectionPtr&, const HttpRequest&);
|
||||
trantor::TcpServer server_;
|
||||
HttpAsyncCallback httpAsyncCallback_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
405
drogon/src/HttpContext.cc
Executable file
405
drogon/src/HttpContext.cc
Executable file
@ -0,0 +1,405 @@
|
||||
// Copyright 2010, Shuo Chen. All rights reserved.
|
||||
// http://code.google.com/p/muduo/
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the License file.
|
||||
|
||||
// Author: Shuo Chen (chenshuo at chenshuo dot com)
|
||||
//
|
||||
|
||||
//taken from muduo and modified
|
||||
//
|
||||
// Copyright 2018, An Tao. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a MIT license
|
||||
// that can be found in the License file.
|
||||
|
||||
|
||||
#include <trantor/utils/MsgBuffer.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include "HttpContext.h"
|
||||
#include <iostream>
|
||||
using namespace trantor;
|
||||
|
||||
bool HttpContext::processRequestLine(const char *begin, const char *end)
|
||||
{
|
||||
bool succeed = false;
|
||||
const char *start = begin;
|
||||
const char *space = std::find(start, end, ' ');
|
||||
if (space != end && request_.setMethod(start, space))
|
||||
{
|
||||
start = space + 1;
|
||||
space = std::find(start, end, ' ');
|
||||
if (space != end)
|
||||
{
|
||||
const char *question = std::find(start, space, '?');
|
||||
if (question != space)
|
||||
{
|
||||
request_.setPath(start, question);
|
||||
request_.setQuery(question + 1, space);
|
||||
}
|
||||
else
|
||||
{
|
||||
request_.setPath(start, space);
|
||||
}
|
||||
start = space + 1;
|
||||
succeed = end - start == 8 && std::equal(start, end - 1, "HTTP/1.");
|
||||
if (succeed)
|
||||
{
|
||||
if (*(end - 1) == '1')
|
||||
{
|
||||
request_.setVersion(HttpRequest::kHttp11);
|
||||
}
|
||||
else if (*(end - 1) == '0')
|
||||
{
|
||||
request_.setVersion(HttpRequest::kHttp10);
|
||||
}
|
||||
else
|
||||
{
|
||||
succeed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return succeed;
|
||||
}
|
||||
|
||||
// return false if any error
|
||||
bool HttpContext::parseRequest(MsgBuffer *buf)
|
||||
{
|
||||
bool ok = true;
|
||||
bool hasMore = true;
|
||||
// std::cout<<std::string(buf->peek(),buf->readableBytes())<<std::endl;
|
||||
while (hasMore)
|
||||
{
|
||||
if (state_ == kExpectRequestLine)
|
||||
{
|
||||
const char *crlf = buf->findCRLF();
|
||||
if (crlf)
|
||||
{
|
||||
ok = processRequestLine(buf->peek(), crlf);
|
||||
if (ok)
|
||||
{
|
||||
//request_.setReceiveTime(receiveTime);
|
||||
buf->retrieveUntil(crlf + 2);
|
||||
state_ = kExpectHeaders;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
else if (state_ == kExpectHeaders)
|
||||
{
|
||||
const char *crlf = buf->findCRLF();
|
||||
if (crlf)
|
||||
{
|
||||
const char *colon = std::find(buf->peek(), crlf, ':');
|
||||
if (colon != crlf)
|
||||
{
|
||||
request_.addHeader(buf->peek(), colon, crlf);
|
||||
}
|
||||
else
|
||||
{
|
||||
// empty line, end of header
|
||||
std::string len = request_.getHeader("Content-Length");
|
||||
LOG_INFO << "content len=" << len;
|
||||
if (len != "")
|
||||
{
|
||||
request_.contentLen = atoi(len.c_str());
|
||||
state_ = kExpectBody;
|
||||
}
|
||||
else
|
||||
{
|
||||
state_ = kGotAll;
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
buf->retrieveUntil(crlf + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
else if (state_ == kExpectBody)
|
||||
{
|
||||
//LOG_INFO << "expectBody:len=" << request_.contentLen;
|
||||
//LOG_INFO << "expectBody:buf=" << buf;
|
||||
if (buf->readableBytes() == 0)
|
||||
{
|
||||
if (request_.contentLen <= 0)
|
||||
{
|
||||
state_ = kGotAll;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (request_.contentLen >= buf->readableBytes())
|
||||
{
|
||||
request_.contentLen -= buf->readableBytes();
|
||||
request_.content_ += std::string(buf->peek(), buf->readableBytes());
|
||||
buf->retrieveAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
request_.content_ += std::string(buf->peek(), request_.contentLen);
|
||||
buf->retrieve(request_.contentLen);
|
||||
request_.contentLen = 0;
|
||||
}
|
||||
if (request_.contentLen <= 0)
|
||||
{
|
||||
state_ = kGotAll;
|
||||
LOG_INFO << "post got all:len=" << request_.content_.length();
|
||||
//LOG_INFO<<"content:"<<request_.content_;
|
||||
LOG_INFO << "content(END)";
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool HttpContext::processResponseLine(const char *begin, const char *end)
|
||||
{
|
||||
const char *start = begin;
|
||||
const char *space = std::find(start, end, ' ');
|
||||
if (space != end)
|
||||
{
|
||||
LOG_DEBUG << *(space - 1);
|
||||
if (*(space - 1) == '1')
|
||||
{
|
||||
response_.setVersion(HttpResponse::kHttp11);
|
||||
}
|
||||
else if (*(space - 1) == '0')
|
||||
{
|
||||
response_.setVersion(HttpResponse::kHttp10);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
start = space + 1;
|
||||
space = std::find(start, end, ' ');
|
||||
if (space != end)
|
||||
{
|
||||
std::string status_code(start, space - start);
|
||||
std::string status_message(space + 1, end - space - 1);
|
||||
LOG_DEBUG << status_code << " " << status_message;
|
||||
switch (atoi(status_code.c_str()))
|
||||
{
|
||||
case 200:
|
||||
response_.setStatusCode(HttpResponse::k200Ok, status_message);
|
||||
break;
|
||||
case 301:
|
||||
response_.setStatusCode(HttpResponse::k301MovedPermanently, status_message);
|
||||
break;
|
||||
case 302:
|
||||
response_.setStatusCode(HttpResponse::k302Found, status_message);
|
||||
break;
|
||||
case 304:
|
||||
response_.setStatusCode(HttpResponse::k304NotModified, status_message);
|
||||
break;
|
||||
case 400:
|
||||
response_.setStatusCode(HttpResponse::k400BadRequest, status_message);
|
||||
break;
|
||||
case 404:
|
||||
response_.setStatusCode(HttpResponse::k404NotFound, status_message);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// return false if any error
|
||||
bool HttpContext::parseResponse(MsgBuffer *buf)
|
||||
{
|
||||
bool ok = true;
|
||||
bool hasMore = true;
|
||||
// std::cout<<std::string(buf->peek(),buf->readableBytes())<<std::endl;
|
||||
//LOG_INFO<<"response message:"<<std::string(buf->peek(),buf->readableBytes());
|
||||
while (hasMore)
|
||||
{
|
||||
//LOG_DEBUG<<"res_state_: "<<(int)res_state_;
|
||||
if (res_state_ == HttpResponseParseState::kExpectResponseLine)
|
||||
{
|
||||
const char *crlf = buf->findCRLF();
|
||||
if (crlf)
|
||||
{
|
||||
ok = processResponseLine(buf->peek(), crlf);
|
||||
if (ok)
|
||||
{
|
||||
//response_.setReceiveTime(receiveTime);
|
||||
buf->retrieveUntil(crlf + 2);
|
||||
res_state_ = HttpResponseParseState::kExpectHeaders;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
else if (res_state_ == HttpResponseParseState::kExpectHeaders)
|
||||
{
|
||||
const char *crlf = buf->findCRLF();
|
||||
if (crlf)
|
||||
{
|
||||
const char *colon = std::find(buf->peek(), crlf, ':');
|
||||
if (colon != crlf)
|
||||
{
|
||||
response_.addHeader(buf->peek(), colon, crlf);
|
||||
}
|
||||
else
|
||||
{
|
||||
// empty line, end of header
|
||||
// FIXME:
|
||||
std::string len = response_.getHeader("Content-Length");
|
||||
LOG_INFO << "content len=" << len;
|
||||
if (len != "")
|
||||
{
|
||||
response_.left_body_length_ = atoi(len.c_str());
|
||||
res_state_ = HttpResponseParseState::kExpectBody;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string encode = response_.getHeader("Transfer-Encoding");
|
||||
if (encode == "chunked")
|
||||
{
|
||||
res_state_ = HttpResponseParseState::kExpectChunkLen;
|
||||
hasMore = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
res_state_ = HttpResponseParseState::kExpectClose;
|
||||
hasMore = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf->retrieveUntil(crlf + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
else if (res_state_ == HttpResponseParseState::kExpectBody)
|
||||
{
|
||||
//LOG_INFO << "expectBody:len=" << request_.contentLen;
|
||||
//LOG_INFO << "expectBody:buf=" << buf;
|
||||
if (buf->readableBytes() == 0)
|
||||
{
|
||||
if (response_.left_body_length_ <= 0)
|
||||
{
|
||||
res_state_ = HttpResponseParseState::kGotAll;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (response_.left_body_length_ >= buf->readableBytes())
|
||||
{
|
||||
response_.left_body_length_ -= buf->readableBytes();
|
||||
response_.body_ += std::string(buf->peek(), buf->readableBytes());
|
||||
buf->retrieveAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
response_.body_ += std::string(buf->peek(), response_.left_body_length_);
|
||||
buf->retrieve(request_.contentLen);
|
||||
response_.left_body_length_ = 0;
|
||||
}
|
||||
if (response_.left_body_length_ <= 0)
|
||||
{
|
||||
res_state_ = HttpResponseParseState::kGotAll;
|
||||
LOG_INFO << "post got all:len=" << response_.left_body_length_;
|
||||
//LOG_INFO<<"content:"<<request_.content_;
|
||||
LOG_INFO << "content(END)";
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
else if (res_state_ == HttpResponseParseState::kExpectClose)
|
||||
{
|
||||
response_.body_ += std::string(buf->peek(), buf->readableBytes());
|
||||
buf->retrieveAll();
|
||||
break;
|
||||
}
|
||||
else if (res_state_ == HttpResponseParseState::kExpectChunkLen)
|
||||
{
|
||||
const char *crlf = buf->findCRLF();
|
||||
if (crlf)
|
||||
{
|
||||
//chunk length line
|
||||
std::string len(buf->peek(), crlf - buf->peek());
|
||||
char *end;
|
||||
response_.current_chunk_length_ = strtol(len.c_str(), &end, 16);
|
||||
LOG_DEBUG << "chun length : " << response_.current_chunk_length_;
|
||||
if (response_.current_chunk_length_ != 0)
|
||||
{
|
||||
res_state_ = HttpResponseParseState::kExpectChunkBody;
|
||||
}
|
||||
else
|
||||
{
|
||||
res_state_ = HttpResponseParseState::kExpectLastEmptyChunk;
|
||||
}
|
||||
buf->retrieveUntil(crlf + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
else if (res_state_ == HttpResponseParseState::kExpectChunkBody)
|
||||
{
|
||||
const char *crlf = buf->findCRLF();
|
||||
if (crlf)
|
||||
{
|
||||
if (response_.current_chunk_length_ == crlf - buf->peek())
|
||||
{
|
||||
//current chunk end crlf
|
||||
response_.body_ += std::string(buf->peek(), response_.current_chunk_length_);
|
||||
buf->retrieveUntil(crlf + 2);
|
||||
response_.current_chunk_length_ = 0;
|
||||
res_state_ = HttpResponseParseState::kExpectChunkLen;
|
||||
}
|
||||
else if (response_.current_chunk_length_ > crlf - buf->peek())
|
||||
{
|
||||
//current chunk body crlf
|
||||
response_.body_ += std::string(buf->peek(), crlf - buf->peek() + 1);
|
||||
buf->retrieveUntil(crlf + 2);
|
||||
response_.current_chunk_length_ -= (crlf - buf->peek() + 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
else if (res_state_ == HttpResponseParseState::kExpectLastEmptyChunk)
|
||||
{
|
||||
//last empty chunk
|
||||
const char *crlf = buf->findCRLF();
|
||||
if (crlf)
|
||||
{
|
||||
buf->retrieveUntil(crlf + 2);
|
||||
res_state_ = HttpResponseParseState::kGotAll;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
119
drogon/src/HttpContext.h
Executable file
119
drogon/src/HttpContext.h
Executable file
@ -0,0 +1,119 @@
|
||||
// Copyright 2010, Shuo Chen. All rights reserved.
|
||||
// http://code.google.com/p/muduo/
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the License file.
|
||||
|
||||
// Author: Shuo Chen (chenshuo at chenshuo dot com)
|
||||
//
|
||||
// This is an internal header file, you should not include this.
|
||||
|
||||
//taken from muduo and modified
|
||||
//
|
||||
// Copyright 2018, An Tao. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a MIT license
|
||||
// that can be found in the License file.
|
||||
|
||||
#ifndef MUDUO_NET_HTTP_HTTPCONTEXT_H
|
||||
#define MUDUO_NET_HTTP_HTTPCONTEXT_H
|
||||
#include "HttpRequest.h"
|
||||
#include "HttpResponse.h"
|
||||
#include <trantor/utils/MsgBuffer.h>
|
||||
|
||||
using namespace trantor;
|
||||
class HttpContext
|
||||
{
|
||||
public:
|
||||
enum HttpRequestParseState
|
||||
{
|
||||
kExpectRequestLine,
|
||||
kExpectHeaders,
|
||||
kExpectBody,
|
||||
kGotAll,
|
||||
};
|
||||
|
||||
enum class HttpResponseParseState
|
||||
{
|
||||
kExpectResponseLine,
|
||||
kExpectHeaders,
|
||||
kExpectBody,
|
||||
kExpectChunkLen,
|
||||
kExpectChunkBody,
|
||||
kExpectLastEmptyChunk,
|
||||
kExpectClose,
|
||||
kGotAll,
|
||||
};
|
||||
|
||||
HttpContext()
|
||||
: state_(kExpectRequestLine),
|
||||
res_state_(HttpResponseParseState::kExpectResponseLine)
|
||||
{
|
||||
}
|
||||
|
||||
// default copy-ctor, dtor and assignment are fine
|
||||
|
||||
// return false if any error
|
||||
bool parseRequest(MsgBuffer *buf);
|
||||
bool parseResponse(MsgBuffer *buf);
|
||||
|
||||
bool gotAll() const
|
||||
{
|
||||
return state_ == kGotAll;
|
||||
}
|
||||
|
||||
bool resGotAll() const
|
||||
{
|
||||
return res_state_ == HttpResponseParseState::kGotAll;
|
||||
}
|
||||
|
||||
bool resExpectResponseLine() const
|
||||
{
|
||||
return res_state_ == HttpResponseParseState::kExpectResponseLine;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
state_ = kExpectRequestLine;
|
||||
HttpRequest dummy;
|
||||
request_.swap(dummy);
|
||||
}
|
||||
|
||||
void resetRes()
|
||||
{
|
||||
res_state_ = HttpResponseParseState::kExpectResponseLine;
|
||||
response_.clear();
|
||||
}
|
||||
|
||||
const HttpRequest &request() const
|
||||
{
|
||||
return request_;
|
||||
}
|
||||
|
||||
HttpRequest &request()
|
||||
{
|
||||
return request_;
|
||||
}
|
||||
|
||||
const HttpResponse &response() const
|
||||
{
|
||||
return response_;
|
||||
}
|
||||
|
||||
HttpResponse &response()
|
||||
{
|
||||
return response_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool processRequestLine(const char *begin, const char *end);
|
||||
bool processResponseLine(const char *begin, const char *end);
|
||||
|
||||
HttpRequestParseState state_;
|
||||
HttpRequest request_;
|
||||
|
||||
HttpResponseParseState res_state_;
|
||||
HttpResponse response_;
|
||||
};
|
||||
|
||||
#endif // MUDUO_NET_HTTP_HTTPCONTEXT_H
|
185
drogon/src/HttpRequest.cc
Executable file
185
drogon/src/HttpRequest.cc
Executable file
@ -0,0 +1,185 @@
|
||||
// Copyright 2010, Shuo Chen. All rights reserved.
|
||||
// http://code.google.com/p/muduo/
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the License file.
|
||||
|
||||
// Author: Shuo Chen (chenshuo at chenshuo dot com)
|
||||
//
|
||||
|
||||
//taken from muduo and modified
|
||||
//
|
||||
// Copyright 2018, An Tao. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a MIT license
|
||||
// that can be found in the License file.
|
||||
|
||||
#include "HttpRequest.h"
|
||||
//解url编码实现
|
||||
#include <iostream>
|
||||
static int urldecode(const char* encd,char* decd)
|
||||
{
|
||||
int j,i;
|
||||
char *cd =(char*) encd;
|
||||
char p[2];
|
||||
unsigned int num;
|
||||
j=0;
|
||||
|
||||
for( i = 0; i < strlen(cd); i++ )
|
||||
{
|
||||
memset( p,0,2);
|
||||
if( cd[i] != '%' )
|
||||
{
|
||||
if(cd[i]=='+')
|
||||
decd[j++]=' ';
|
||||
else
|
||||
decd[j++] = cd[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
p[0] = cd[++i];
|
||||
p[1] = cd[++i];
|
||||
|
||||
p[0] = p[0] - 48 - ((p[0] >= 'A') ? 7 : 0) - ((p[0] >= 'a') ? 32 : 0);
|
||||
p[1] = p[1] - 48 - ((p[1] >= 'A') ? 7 : 0) - ((p[1] >= 'a') ? 32 : 0);
|
||||
decd[j++] = (unsigned char)(p[0] * 16 + p[1]);
|
||||
|
||||
}
|
||||
|
||||
decd[j] = 0;
|
||||
return j;
|
||||
}
|
||||
void HttpRequest::parsePremeter()
|
||||
{
|
||||
const std::string &type=getHeader("Content-Type");
|
||||
const std::string &input=query();
|
||||
if(method_==kGet||(method_==kPost&&(type==""||type.find("application/x-www-form-urlencoded")!=std::string::npos)))
|
||||
{
|
||||
|
||||
std::string::size_type pos=0;
|
||||
while((input[pos]=='?'||isspace(input[pos]))&&pos<input.length())
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
std::string value=input.substr(pos);
|
||||
while((pos = value.find("&")) != std::string::npos) {
|
||||
std::string coo = value.substr(0, pos);
|
||||
auto epos = coo.find("=");
|
||||
if(epos != std::string::npos) {
|
||||
std::string key = coo.substr(0, epos);
|
||||
std::string::size_type cpos=0;
|
||||
while(isspace(key[cpos])&&cpos<key.length())
|
||||
cpos++;
|
||||
key=key.substr(cpos);
|
||||
std::string pvalue = coo.substr(epos + 1);
|
||||
std::string pdecode=pvalue;
|
||||
std::string keydecode=key;
|
||||
int ret=urldecode((char *)key.c_str(),(char *)keydecode.c_str());
|
||||
keydecode=keydecode.substr(0,ret);
|
||||
ret=urldecode((char *)pvalue.c_str(),(char *)pdecode.c_str());
|
||||
pdecode=pdecode.substr(0,ret);
|
||||
premeter_[keydecode] = pdecode;
|
||||
}
|
||||
value=value.substr(pos+1);
|
||||
}
|
||||
if(value.length()>0)
|
||||
{
|
||||
std::string &coo = value;
|
||||
auto epos = coo.find("=");
|
||||
if(epos != std::string::npos) {
|
||||
std::string key = coo.substr(0, epos);
|
||||
std::string::size_type cpos=0;
|
||||
while(isspace(key[cpos])&&cpos<key.length())
|
||||
cpos++;
|
||||
key=key.substr(cpos);
|
||||
std::string pvalue = coo.substr(epos + 1);
|
||||
std::string pdecode=pvalue;
|
||||
std::string keydecode=key;
|
||||
int ret=urldecode((char *)key.c_str(),(char *)keydecode.c_str());
|
||||
keydecode=keydecode.substr(0,ret);
|
||||
ret=urldecode((char *)pvalue.c_str(),(char *)pdecode.c_str());
|
||||
pdecode=pdecode.substr(0,ret);
|
||||
premeter_[keydecode] = pdecode;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_DEBUG<<"premeter:";
|
||||
for(auto iter:premeter_)
|
||||
{
|
||||
LOG_DEBUG<<iter.first<<"="<<iter.second;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HttpRequest::appendToBuffer(MsgBuffer* output) const
|
||||
{
|
||||
switch(method_)
|
||||
{
|
||||
case kDelete:
|
||||
output->append("DELETE ");
|
||||
break;
|
||||
case kGet:
|
||||
output->append("GET ");
|
||||
break;
|
||||
case kHead:
|
||||
output->append("HEAD ");
|
||||
break;
|
||||
case kPost:
|
||||
output->append("POST ");
|
||||
break;
|
||||
case kPut:
|
||||
output->append("PUT ");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if(path_.size() != 0)
|
||||
{
|
||||
output->append(path_);
|
||||
output->append(" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
output->append("/ ");
|
||||
}
|
||||
|
||||
if(version_ == kHttp11)
|
||||
{
|
||||
output->append("HTTP/1.1");
|
||||
}
|
||||
else if(version_ == kHttp10)
|
||||
{
|
||||
output->append("HTTP/1.0");
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
output->append("\r\n");
|
||||
|
||||
for (std::map<std::string, std::string>::const_iterator it = headers_.begin();
|
||||
it != headers_.end();
|
||||
++it) {
|
||||
output->append(it->first);
|
||||
output->append(": ");
|
||||
output->append(it->second);
|
||||
output->append("\r\n");
|
||||
}
|
||||
if(cookies_.size() > 0) {
|
||||
output->append("Set-Cookie: ");
|
||||
for(auto it = cookies_.begin(); it != cookies_.end(); it++) {
|
||||
output->append(it->first);
|
||||
output->append("= ");
|
||||
output->append(it->second);
|
||||
output->append(";");
|
||||
}
|
||||
output->unwrite(1);//delete last ';'
|
||||
output->append("\r\n");
|
||||
}
|
||||
|
||||
output->append("\r\n");
|
||||
|
||||
//LOG_INFO<<"request(no body):"<<output->peek();
|
||||
output->append(content_);
|
||||
}
|
176
drogon/src/HttpResponse.cc
Executable file
176
drogon/src/HttpResponse.cc
Executable file
@ -0,0 +1,176 @@
|
||||
// Copyright 2010, Shuo Chen. All rights reserved.
|
||||
// http://code.google.com/p/muduo/
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the License file.
|
||||
|
||||
// Author: Shuo Chen (chenshuo at chenshuo dot com)
|
||||
//
|
||||
|
||||
//taken from muduo and modified
|
||||
//
|
||||
// Copyright 2018, An Tao. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a MIT license
|
||||
// that can be found in the License file.
|
||||
|
||||
#include "HttpResponse.h"
|
||||
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace trantor;
|
||||
const std::string HttpResponse::web_content_type_to_string(uint8_t contenttype)
|
||||
{
|
||||
switch(contenttype) {
|
||||
case CT_TEXT_HTML:
|
||||
return "text/html; charset=utf-8";
|
||||
|
||||
case CT_APPLICATION_XML:
|
||||
return "application/xml; charset=utf-8";
|
||||
|
||||
case CT_APPLICATION_JSON:
|
||||
return "application/json; charset=utf-8";
|
||||
|
||||
case CT_APPLICATION_X_JAVASCRIPT:
|
||||
return "application/x-javascript; charset=utf-8";
|
||||
|
||||
case CT_TEXT_CSS:
|
||||
return "text/css; charset=utf-8";
|
||||
|
||||
case CT_TEXT_XML:
|
||||
return "text/xml; charset=utf-8";
|
||||
|
||||
case CT_TEXT_XSL:
|
||||
return "text/xsl; charset=utf-8";
|
||||
|
||||
case CT_APPLICATION_OCTET_STREAM:
|
||||
return "application/octet-stream";
|
||||
|
||||
case CT_IMAGE_SVG_XML:
|
||||
return "image/svg+xml";
|
||||
|
||||
case CT_APPLICATION_X_FONT_TRUETYPE:
|
||||
return "application/x-font-truetype";
|
||||
|
||||
case CT_APPLICATION_X_FONT_OPENTYPE:
|
||||
return "application/x-font-opentype";
|
||||
|
||||
case CT_APPLICATION_FONT_WOFF:
|
||||
return "application/font-woff";
|
||||
|
||||
case CT_APPLICATION_FONT_WOFF2:
|
||||
return "application/font-woff2";
|
||||
|
||||
case CT_APPLICATION_VND_MS_FONTOBJ:
|
||||
return "application/vnd.ms-fontobject";
|
||||
|
||||
case CT_IMAGE_PNG:
|
||||
return "image/png";
|
||||
|
||||
case CT_IMAGE_JPG:
|
||||
return "image/jpeg";
|
||||
|
||||
case CT_IMAGE_GIF:
|
||||
return "image/gif";
|
||||
|
||||
case CT_IMAGE_XICON:
|
||||
return "image/x-icon";
|
||||
|
||||
case CT_IMAGE_BMP:
|
||||
return "image/bmp";
|
||||
|
||||
case CT_IMAGE_ICNS:
|
||||
return "image/icns";
|
||||
|
||||
default:
|
||||
case CT_TEXT_PLAIN:
|
||||
return "text/plain; charset=utf-8";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const std::string HttpResponse::web_response_code_to_string(int code)
|
||||
{
|
||||
switch(code) {
|
||||
case 200:
|
||||
return "OK";
|
||||
|
||||
case 304:
|
||||
return "Not Modified";
|
||||
case 307:
|
||||
return "Temporary Redirect";
|
||||
|
||||
case 400:
|
||||
return "Bad Request";
|
||||
|
||||
case 403:
|
||||
return "Forbidden";
|
||||
|
||||
case 404:
|
||||
return "Not Found";
|
||||
|
||||
case 412:
|
||||
return "Preconditions Failed";
|
||||
|
||||
default:
|
||||
if(code >= 100 && code < 200)
|
||||
return "Informational";
|
||||
|
||||
if(code >= 200 && code < 300)
|
||||
return "Successful";
|
||||
|
||||
if(code >= 300 && code < 400)
|
||||
return "Redirection";
|
||||
|
||||
if(code >= 400 && code < 500)
|
||||
return "Bad Request";
|
||||
|
||||
if(code >= 500 && code < 600)
|
||||
return "Server Error";
|
||||
|
||||
return "Undefined Error";
|
||||
}
|
||||
}
|
||||
void HttpResponse::appendToBuffer(MsgBuffer* output) const
|
||||
{
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_);
|
||||
output->append(buf);
|
||||
output->append(statusMessage_);
|
||||
output->append("\r\n");
|
||||
|
||||
if (closeConnection_) {
|
||||
output->append("Connection: close\r\n");
|
||||
} else {
|
||||
snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", body_.size());
|
||||
output->append(buf);
|
||||
output->append("Connection: Keep-Alive\r\n");
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::string>::const_iterator it = headers_.begin();
|
||||
it != headers_.end();
|
||||
++it) {
|
||||
output->append(it->first);
|
||||
output->append(": ");
|
||||
output->append(it->second);
|
||||
output->append("\r\n");
|
||||
}
|
||||
if(cookies_.size() > 0) {
|
||||
output->append("Set-Cookie: ");
|
||||
for(auto it = cookies_.begin(); it != cookies_.end(); it++) {
|
||||
output->append(it->first);
|
||||
output->append("= ");
|
||||
output->append(it->second);
|
||||
output->append(";");
|
||||
}
|
||||
output->unwrite(1);//delete last ';'
|
||||
output->append("\r\n");
|
||||
}
|
||||
|
||||
output->append("\r\n");
|
||||
|
||||
LOG_INFO<<"reponse(no body):"<<output->peek();
|
||||
output->append(body_);
|
||||
|
||||
}
|
109
drogon/src/HttpServer.cc
Executable file
109
drogon/src/HttpServer.cc
Executable file
@ -0,0 +1,109 @@
|
||||
// Copyright 2010, Shuo Chen. All rights reserved.
|
||||
// http://code.google.com/p/muduo/
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the License file.
|
||||
|
||||
// Author: Shuo Chen (chenshuo at chenshuo dot com)
|
||||
//
|
||||
|
||||
//taken from muduo and modified
|
||||
//
|
||||
// Copyright 2018, An Tao. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a MIT license
|
||||
// that can be found in the License file.
|
||||
|
||||
#include "HttpServer.h"
|
||||
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include "HttpContext.h"
|
||||
#include "HttpRequest.h"
|
||||
#include "HttpResponse.h"
|
||||
#include <functional>
|
||||
|
||||
using namespace std::placeholders;
|
||||
using namespace drogon;
|
||||
using namespace trantor;
|
||||
|
||||
|
||||
static void defaultHttpAsyncCallback(const HttpRequest&, std::function<void( HttpResponse& resp)>callback)
|
||||
{
|
||||
HttpResponse resp(true);
|
||||
resp.setStatusCode(HttpResponse::k404NotFound);
|
||||
resp.setCloseConnection(true);
|
||||
callback(resp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
HttpServer::HttpServer(EventLoop* loop,
|
||||
const InetAddress& listenAddr,
|
||||
const std::string& name)
|
||||
: server_(loop, listenAddr, name.c_str()),
|
||||
httpAsyncCallback_(defaultHttpAsyncCallback)
|
||||
{
|
||||
server_.setConnectionCallback(
|
||||
std::bind(&HttpServer::onConnection, this, _1));
|
||||
server_.setRecvMessageCallback(
|
||||
std::bind(&HttpServer::onMessage, this, _1, _2));
|
||||
}
|
||||
|
||||
HttpServer::~HttpServer()
|
||||
{
|
||||
}
|
||||
|
||||
void HttpServer::start()
|
||||
{
|
||||
LOG_WARN << "HttpServer[" << server_.name()
|
||||
<< "] starts listenning on " << server_.ipPort();
|
||||
server_.start();
|
||||
}
|
||||
|
||||
void HttpServer::onConnection(const TcpConnectionPtr& conn)
|
||||
{
|
||||
if (conn->connected()) {
|
||||
conn->setContext(new HttpContext());
|
||||
}
|
||||
}
|
||||
|
||||
void HttpServer::onMessage(const TcpConnectionPtr& conn,
|
||||
MsgBuffer* buf)
|
||||
{
|
||||
HttpContext* context = (HttpContext*)(conn->getContext());
|
||||
|
||||
// LOG_INFO << "###:" << string(buf->peek(), buf->readableBytes());
|
||||
if (!context->parseRequest(buf)) {
|
||||
conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
|
||||
conn->shutdown();
|
||||
}
|
||||
|
||||
if (context->gotAll()) {
|
||||
context->request().parsePremeter();
|
||||
onRequest(conn, context->request());
|
||||
context->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req)
|
||||
{
|
||||
const std::string& connection = req.getHeader("Connection");
|
||||
bool close = connection == "close" ||
|
||||
(req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive");
|
||||
|
||||
|
||||
|
||||
httpAsyncCallback_(req, [ = ](HttpResponse & response) {
|
||||
MsgBuffer buf;
|
||||
response.setCloseConnection(close);
|
||||
response.appendToBuffer(&buf);
|
||||
conn->send(buf.peek(),buf.readableBytes());
|
||||
if (response.closeConnection()) {
|
||||
conn->shutdown();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,41 @@
|
||||
#include <trantor/net/TcpServer.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <trantor/net/EventLoopThread.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
using namespace trantor;
|
||||
#define USE_IPV6 0
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
LOG_DEBUG<<"test start";
|
||||
Logger::setLogLevel(Logger::TRACE);
|
||||
//EventLoopThread loopThread;
|
||||
EventLoop loop;
|
||||
//loopThread.run();
|
||||
#if USE_IPV6
|
||||
InetAddress addr(7676,true,true);
|
||||
#else
|
||||
InetAddress addr(7676);
|
||||
#endif
|
||||
TcpServer server(&loop,addr,"test");
|
||||
server.setRecvMessageCallback([](const TcpConnectionPtr &connectionPtr,MsgBuffer *buffer){
|
||||
//LOG_DEBUG<<"recv callback!";
|
||||
std::cout<<std::string(buffer->peek(),buffer->readableBytes());
|
||||
connectionPtr->send(buffer->peek(),buffer->readableBytes());
|
||||
buffer->retrieveAll();
|
||||
connectionPtr->forceClose();
|
||||
});
|
||||
server.setConnectionCallback([](const TcpConnectionPtr& connPtr){
|
||||
if(connPtr->connected())
|
||||
{
|
||||
LOG_DEBUG<<"New connection";
|
||||
}
|
||||
else if(connPtr->disconnected())
|
||||
{
|
||||
LOG_DEBUG<<"connection disconnected";
|
||||
}
|
||||
});
|
||||
server.setIoLoopNum(3);
|
||||
server.start();
|
||||
loop.loop();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user