├── third_party ├── CxxJDK ├── CxxFiber └── CxxLog4j ├── img ├── fiber.png └── ioflow.png ├── CHANGELOG.md ├── test ├── main.cpp ├── benchmark.cpp ├── Makefile_unix ├── httpserver.cpp └── testnaf.cpp ├── http ├── source │ ├── empty_string.h │ ├── enum_to_int.h │ ├── to_lower_table.cc │ ├── const_singleton.h │ ├── to_lower_table.h │ ├── buffer_impl.h │ ├── time.h │ ├── codes.h │ ├── exception.h │ ├── macros.h │ ├── buffer_impl.cc │ ├── linked_object.h │ ├── codes.cc │ ├── header_map_impl.h │ ├── headers.h │ ├── utility.cc │ ├── utility.h │ ├── http2 │ │ └── codec_impl.h │ └── http1 │ │ └── codec_impl.h └── include │ ├── protocol.h │ ├── buffer.h │ └── codes.h ├── filter └── http │ ├── EHttpRequest.cpp │ ├── EHttpResponse.cpp │ ├── EHttpRequest.hh │ ├── EHttpCodecFilter.hh │ ├── EHttpResponse.hh │ └── EHttpCodecFilter.cpp ├── src ├── EHttpRequest.cpp ├── EHttpResponse.cpp ├── EIoFilterAdapter.cpp ├── EHttpHandler.cpp ├── EManagedSession.hh ├── ESocketSession.cpp ├── EIoSession.cpp ├── ESubnet.cpp ├── EBlacklistFilter.cpp ├── EWhitelistFilter.cpp ├── EHttpAcceptor.cpp ├── EHttpSession.cpp ├── EIoFilterChainBuidler.cpp └── EIoServiceStatistics.cpp ├── ENaf.hh ├── inc ├── EHttpRequest.hh ├── EHttpResponse.hh ├── EIoFilterAdapter.hh ├── EHttpAcceptor.hh ├── EHttpHandler.hh ├── EIoService.hh ├── ESubnet.hh ├── ESocketSession.hh ├── EHttpSession.hh ├── EBlacklistFilter.hh ├── EWhitelistFilter.hh ├── EIoFilter.hh ├── EIoFilterChainBuilder.hh ├── EIoSession.hh ├── ESocketAcceptor.hh ├── EIoServiceStatistics.hh └── EIoFilterChain.hh └── README.md /third_party/CxxJDK: -------------------------------------------------------------------------------- 1 | ../../CxxJDK -------------------------------------------------------------------------------- /third_party/CxxFiber: -------------------------------------------------------------------------------- 1 | ../../CxxFiber/ -------------------------------------------------------------------------------- /third_party/CxxLog4j: -------------------------------------------------------------------------------- 1 | ../../CxxLog4j/ -------------------------------------------------------------------------------- /img/fiber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxxjava/CxxConet/HEAD/img/fiber.png -------------------------------------------------------------------------------- /img/ioflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cxxjava/CxxConet/HEAD/img/ioflow.png -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2018/10/26 2 | 3 | 1. 添加http & http2(h2&h2c)的支持; 4 | 2. 支持http2的协议自动协商; 5 | 3. 支持HttpServlet编程模型(参考示例:test/httpserver.cpp); 6 | 4. HttpServlet同时支持线程池 or 协程池; -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include "es_main.h" 2 | 3 | int main(int argc, const char **argv) { 4 | 5 | MAIN_CALL(testnaf); 6 | // MAIN_CALL(testnaf_benchmark); 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /http/source/empty_string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace efc { 6 | namespace naf { 7 | namespace Http { 8 | 9 | static const std::string EMPTY_STRING = ""; 10 | 11 | } // namespace http 12 | } // namespace naf 13 | } // namespace efc 14 | -------------------------------------------------------------------------------- /http/source/enum_to_int.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace efc { 6 | namespace naf { 7 | namespace Http { 8 | 9 | /** 10 | * Convert an int based enum to an int. 11 | */ 12 | template uint32_t enumToInt(T val) { return static_cast(val); } 13 | 14 | } // namespace Http 15 | } // namespace naf 16 | } // namespace efc 17 | -------------------------------------------------------------------------------- /filter/http/EHttpRequest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpRequest.cpp 3 | * 4 | * Created on: 2017-4-21 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "./EHttpRequest.hh" 9 | 10 | namespace efc { 11 | namespace naf { 12 | namespace filter { 13 | namespace http { 14 | 15 | } /* namespace http */ 16 | } /* namespace filter */ 17 | } /* namespace naf */ 18 | } /* namespace efc */ 19 | -------------------------------------------------------------------------------- /filter/http/EHttpResponse.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpResponse.cpp 3 | * 4 | * Created on: 2017-4-21 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "./EHttpResponse.hh" 9 | 10 | namespace efc { 11 | namespace naf { 12 | namespace filter { 13 | namespace http { 14 | 15 | } /* namespace http */ 16 | } /* namespace filter */ 17 | } /* namespace naf */ 18 | } /* namespace efc */ 19 | -------------------------------------------------------------------------------- /http/include/protocol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace efc { 4 | namespace naf { 5 | namespace Http { 6 | 7 | /** 8 | * Possible HTTP connection/request protocols. The parallel NumProtocols constant allows defining 9 | * fixed arrays for each protocol, but does not pollute the enum. 10 | */ 11 | enum class Protocol { Http10, Http11, Http2 }; 12 | const size_t NumProtocols = 3; 13 | 14 | } // namespace http 15 | } // namespace naf 16 | } // namespace efc 17 | -------------------------------------------------------------------------------- /src/EHttpRequest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpRequest.cpp 3 | * 4 | * Created on: 2018-7-4 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EHttpRequest.hh" 9 | #include "../inc/EHttpSession.hh" 10 | 11 | namespace efc { 12 | namespace naf { 13 | 14 | EHttpRequest::EHttpRequest(ActiveStream* as, Http::HeaderMapPtr hm) : stream(as), headerMap(hm) { 15 | // 16 | } 17 | 18 | ActiveStream* EHttpRequest::getHttpStream() { 19 | return stream; 20 | } 21 | 22 | } /* namespace naf */ 23 | } /* namespace efc */ 24 | -------------------------------------------------------------------------------- /http/source/to_lower_table.cc: -------------------------------------------------------------------------------- 1 | #include "./to_lower_table.h" 2 | 3 | namespace efc { 4 | namespace naf { 5 | namespace Http { 6 | 7 | ToLowerTable::ToLowerTable() { 8 | for (size_t c = 0; c < 256; c++) { 9 | table_[c] = c; 10 | if ((c >= 'A') && (c <= 'Z')) { 11 | table_[c] |= 0x20; 12 | } 13 | } 14 | } 15 | 16 | void ToLowerTable::toLowerCase(char* buffer, uint32_t size) const { 17 | for (size_t i = 0; i < size; i++) { 18 | buffer[i] = table_[static_cast(buffer[i])]; 19 | } 20 | } 21 | 22 | } // namespace http 23 | } // namespace naf 24 | } // namespace efc 25 | -------------------------------------------------------------------------------- /http/source/const_singleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace efc { 4 | namespace naf { 5 | namespace Http { 6 | 7 | /** 8 | * ConstSingleton allows easy global cross-thread access to a const object. 9 | * 10 | * This singleton should be used for data which is initialized once at 11 | * start-up and then be treated as immutable const data thereafter. 12 | */ 13 | template class ConstSingleton { 14 | public: 15 | /** 16 | * Obtain an instance of the singleton for class T. 17 | * @return const T& a reference to the singleton for class T. 18 | */ 19 | static const T& get() { 20 | static T* instance = new T(); 21 | return *instance; 22 | } 23 | }; 24 | 25 | } // namespace http 26 | } // namespace naf 27 | } // namespace efc 28 | -------------------------------------------------------------------------------- /ENaf.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * ENaf.hh 3 | * 4 | * Created on: 2017-3-16 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef __ENAF_HH__ 9 | #define __ENAF_HH__ 10 | 11 | #define ENAF_VERSION "0.4.0" 12 | 13 | #include "Efc.hh" 14 | 15 | //core 16 | #include "./inc/EIoBuffer.hh" 17 | #include "./inc/EIoFilter.hh" 18 | #include "./inc/EIoFilterAdapter.hh" 19 | #include "./inc/EIoFilterChain.hh" 20 | #include "./inc/EIoFilterChainBuilder.hh" 21 | #include "./inc/EIoService.hh" 22 | #include "./inc/EIoSession.hh" 23 | #include "./inc/ESubnet.hh" 24 | #include "./inc/ESocketSession.hh" 25 | #include "./inc/ESocketAcceptor.hh" 26 | #include "./inc/EBlacklistFilter.hh" 27 | #include "./inc/EWhitelistFilter.hh" 28 | 29 | using namespace efc::naf; 30 | 31 | #endif // !__ENAF_HH__ 32 | -------------------------------------------------------------------------------- /src/EHttpResponse.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpResponse.cpp 3 | * 4 | * Created on: 2018-7-4 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EHttpResponse.hh" 9 | 10 | #include "../http/include/codes.h" 11 | #include "../http/source/headers.h" 12 | #include "../http/source/buffer_impl.h" 13 | 14 | namespace efc { 15 | namespace naf { 16 | 17 | EHttpResponse::EHttpResponse(ActiveStream* as) : 18 | stream(as), headerMap{{Http::Headers::get().Status, std::to_string((int)Http::Code::OK)}} { 19 | // 20 | } 21 | 22 | ActiveStream* EHttpResponse::getHttpStream() { 23 | return stream; 24 | } 25 | 26 | Http::HeaderMap& EHttpResponse::getHeaderMap() { 27 | return headerMap; 28 | } 29 | 30 | void EHttpResponse::write(const void* data, int len) { 31 | if (bodyData == null) { 32 | bodyData = EIoBuffer::allocate(256); 33 | } 34 | bodyData->put(data, len); 35 | } 36 | 37 | } /* namespace naf */ 38 | } /* namespace efc */ 39 | -------------------------------------------------------------------------------- /http/source/to_lower_table.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace efc { 7 | namespace naf { 8 | namespace Http { 9 | 10 | /** 11 | * Convenience class for converting ASCII strings to lower case using a lookup table for maximum 12 | * speed. 13 | */ 14 | class ToLowerTable { 15 | public: 16 | ToLowerTable(); 17 | 18 | /** 19 | * Convert a string to lower case. 20 | * @param buffer supplies the start of the string. 21 | * @param size supplies the size of the string. 22 | */ 23 | void toLowerCase(char* buffer, uint32_t size) const; 24 | 25 | /** 26 | * Convert a string to lower case. 27 | * @param supplies the string to convert. 28 | */ 29 | void toLowerCase(std::string& string) const { 30 | toLowerCase(&string[0], string.size()); 31 | } 32 | 33 | private: 34 | std::array table_; 35 | }; 36 | 37 | } // namespace http 38 | } // namespace naf 39 | } // namespace efc 40 | -------------------------------------------------------------------------------- /inc/EHttpRequest.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpRequest.hh 3 | * 4 | * Created on: 2018-7-4 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EHTTPREQUEST_HH_ 9 | #define EHTTPREQUEST_HH_ 10 | 11 | #include "../http/include/buffer.h" 12 | #include "../http/include/header_map.h" 13 | #include "./EIoBuffer.hh" 14 | 15 | namespace efc { 16 | namespace naf { 17 | 18 | class ActiveStream; 19 | class HttpInputStream; 20 | 21 | class EHttpRequest: public efc::EObject { 22 | public: 23 | EHttpRequest(ActiveStream* stream, Http::HeaderMapPtr headerMap); 24 | 25 | ActiveStream* getHttpStream(); 26 | 27 | Http::HeaderMapPtr getHeaderMap() { return headerMap; } 28 | Http::Buffer::LinkedBuffer getBodyData() { return bodyData; } 29 | 30 | private: 31 | friend class ActiveStream; 32 | 33 | ActiveStream* stream; 34 | Http::HeaderMapPtr headerMap; 35 | Http::Buffer::LinkedBuffer bodyData; 36 | }; 37 | 38 | } /* namespace naf */ 39 | } /* namespace efc */ 40 | #endif /* EHTTPREQUEST_HH_ */ 41 | -------------------------------------------------------------------------------- /inc/EHttpResponse.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpResponse.hh 3 | * 4 | * Created on: 2018-7-4 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EHTTPRESPONSE_HH_ 9 | #define EHTTPRESPONSE_HH_ 10 | 11 | #include "../inc/EIoBuffer.hh" 12 | #include "../http/include/header_map.h" 13 | #include "../http/source/header_map_impl.h" 14 | 15 | namespace efc { 16 | namespace naf { 17 | 18 | class ActiveStream; 19 | class EHttpSession; 20 | 21 | class EHttpResponse: public efc::EObject { 22 | public: 23 | EHttpResponse(ActiveStream* stream); 24 | 25 | ActiveStream* getHttpStream(); 26 | 27 | Http::HeaderMap& getHeaderMap(); 28 | 29 | void write(const void* data, int len); 30 | 31 | private: 32 | friend class EHttpAcceptor; 33 | 34 | ActiveStream* stream; 35 | Http::HeaderMapImpl headerMap; 36 | sp bodyData; 37 | }; 38 | 39 | class EndHttpResponse : public EHttpResponse { 40 | public: 41 | EndHttpResponse(): EHttpResponse(null) {} 42 | }; 43 | 44 | } /* namespace naf */ 45 | } /* namespace efc */ 46 | #endif /* EHTTPRESPONSE_HH_ */ 47 | -------------------------------------------------------------------------------- /src/EIoFilterAdapter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoFilterAdapter.cpp 3 | * 4 | * Created on: 2016-1-22 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EIoFilterAdapter.hh" 9 | #include "../inc/EIoFilterChain.hh" 10 | 11 | namespace efc { 12 | namespace naf { 13 | 14 | boolean EIoFilterAdapter::sessionCreated(EIoFilter::NextFilter* nextFilter, 15 | EIoSession* session) { 16 | return nextFilter->sessionCreated(session); 17 | } 18 | 19 | void EIoFilterAdapter::sessionClosed(EIoFilter::NextFilter* nextFilter, 20 | EIoSession* session) { 21 | nextFilter->sessionClosed(session); 22 | } 23 | 24 | sp EIoFilterAdapter::messageReceived(EIoFilter::NextFilter* nextFilter, 25 | EIoSession* session, sp message) { 26 | return nextFilter->messageReceived(session, message); 27 | } 28 | 29 | sp EIoFilterAdapter::messageSend(EIoFilter::NextFilter* nextFilter, 30 | EIoSession* session, sp message) { 31 | return nextFilter->messageSend(session, message); 32 | } 33 | 34 | EString EIoFilterAdapter::toString() { 35 | return "EIoFilterAdapter"; 36 | } 37 | 38 | } /* namespace naf */ 39 | } /* namespace efc */ 40 | -------------------------------------------------------------------------------- /http/source/buffer_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Efc.hh" 4 | 5 | #include 6 | #include 7 | 8 | #include "../include/buffer.h" 9 | 10 | namespace efc { 11 | namespace naf { 12 | namespace Http { 13 | namespace Buffer { 14 | 15 | /** 16 | * Wraps an allocated and owned evbuffer. 17 | * 18 | * Note that due to the internals of move() accessing buffer(), OwnedImpl is not 19 | * compatible with non-LibEventInstance buffers. 20 | */ 21 | class OwnedImpl: public Instance { 22 | public: 23 | OwnedImpl(); 24 | OwnedImpl(const std::string& data); 25 | OwnedImpl(const void* data, uint64_t size); 26 | 27 | void add(sp& buf) override; 28 | void add(const void* data, uint64_t size) override; 29 | void add(const std::string& data) override; 30 | void clear() override; 31 | uint64_t length() override; 32 | void move(Instance& rhs) override; 33 | void move(Instance& rhs, uint64_t length) override; 34 | 35 | LinkedBuffer& buffer() {return buffer_;} 36 | 37 | private: 38 | LinkedBuffer buffer_; 39 | 40 | uint32_t bufferLimit_ {0}; 41 | }; 42 | 43 | } // namespace buffer 44 | } // namespace http 45 | } // namespace naf 46 | } // namespace efc 47 | -------------------------------------------------------------------------------- /filter/http/EHttpRequest.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpRequest.hh 3 | * 4 | * Created on: 2017-4-21 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EHTTPREQUEST_HH_ 9 | #define EHTTPREQUEST_HH_ 10 | 11 | #include "Efc.hh" 12 | 13 | namespace efc { 14 | namespace naf { 15 | namespace filter { 16 | namespace http { 17 | 18 | class EHttpRequest: public EObject { 19 | public: 20 | EHttpRequest(void* httpData, int headLen, int bodyLen) : 21 | m_HeadLen(headLen), 22 | m_BodyLen(bodyLen) { 23 | m_HttpData.append(httpData, headLen+bodyLen); 24 | } 25 | char* getHttpData() { 26 | return (char*)m_HttpData.data(); 27 | } 28 | int getHttpDataLen() { 29 | return m_HttpData.size(); 30 | } 31 | char* getHeadData() { 32 | return (char*)m_HttpData.data(); 33 | } 34 | int getHeadLen() { 35 | return m_HeadLen; 36 | } 37 | char* getBodyData() { 38 | return (char*)m_HttpData.data() + m_HeadLen; 39 | } 40 | int getBodyLen() { 41 | return m_BodyLen; 42 | } 43 | private: 44 | EByteBuffer m_HttpData; 45 | int m_HeadLen; 46 | int m_BodyLen; 47 | }; 48 | 49 | } /* namespace http */ 50 | } /* namespace filter */ 51 | } /* namespace naf */ 52 | } /* namespace efc */ 53 | #endif /* EHTTPREQUEST_HH_ */ 54 | -------------------------------------------------------------------------------- /http/source/time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace efc { 6 | namespace naf { 7 | namespace Http { 8 | 9 | /** 10 | * Less typing for common system time and steady time type. 11 | * 12 | * SystemTime should be used when getting a time to present to the user, e.g. for logging. 13 | * MonotonicTime should be used when tracking time for computing an interval. 14 | */ 15 | typedef std::chrono::time_point SystemTime; 16 | typedef std::chrono::time_point MonotonicTime; 17 | 18 | /** 19 | * Abstraction for getting the current system time. Useful for testing. 20 | */ 21 | class SystemTimeSource { 22 | public: 23 | virtual ~SystemTimeSource() { 24 | } 25 | 26 | /** 27 | * @return the current system time. 28 | */ 29 | virtual SystemTime currentTime() = 0; 30 | }; 31 | 32 | /** 33 | * Abstraction for getting the current monotonically increasing time. Useful for testing. 34 | */ 35 | class MonotonicTimeSource { 36 | public: 37 | virtual ~MonotonicTimeSource() { 38 | } 39 | 40 | /** 41 | * @return the current monotonic time. 42 | */ 43 | virtual MonotonicTime currentTime() = 0; 44 | }; 45 | 46 | } // namespace Http 47 | } // namespace naf 48 | } // namespace efc 49 | -------------------------------------------------------------------------------- /http/source/codes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../include/codes.h" 8 | #include "../include/header_map.h" 9 | 10 | namespace efc { 11 | namespace naf { 12 | namespace Http { 13 | 14 | /** 15 | * General utility routines for HTTP codes. 16 | */ 17 | class CodeUtility { 18 | public: 19 | 20 | /** 21 | * Convert an HTTP response code to a descriptive string. 22 | * @param code supplies the code to convert. 23 | * @return const char* the string. 24 | */ 25 | static const char* toString(Code code); 26 | 27 | static bool is1xx(uint64_t code) { 28 | return code >= 100 && code < 200; 29 | } 30 | static bool is2xx(uint64_t code) { 31 | return code >= 200 && code < 300; 32 | } 33 | static bool is3xx(uint64_t code) { 34 | return code >= 300 && code < 400; 35 | } 36 | static bool is4xx(uint64_t code) { 37 | return code >= 400 && code < 500; 38 | } 39 | static bool is5xx(uint64_t code) { 40 | return code >= 500 && code < 600; 41 | } 42 | 43 | static bool isGatewayError(uint64_t code) { 44 | return code >= 502 && code < 505; 45 | } 46 | 47 | static std::string groupStringForResponseCode(Code response_code); 48 | }; 49 | 50 | } // namespace http 51 | } // namespace naf 52 | } // namespace efc 53 | -------------------------------------------------------------------------------- /filter/http/EHttpCodecFilter.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpCodecFilter.hh 3 | * 4 | * Created on: 2017-4-7 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EHTTPCODECFILTER_HH_ 9 | #define EHTTPCODECFILTER_HH_ 10 | 11 | #include "../../inc/EIoFilterAdapter.hh" 12 | #include "../../inc/EIoBuffer.hh" 13 | 14 | namespace efc { 15 | namespace naf { 16 | namespace filter { 17 | namespace http { 18 | 19 | class EHttpCodecFilter: public EIoFilterAdapter { 20 | public: 21 | static const int MAX_HTTP_SIZE = 4096; 22 | 23 | public: 24 | /** 25 | * {@inheritDoc} 26 | */ 27 | virtual boolean sessionCreated(EIoFilter::NextFilter* nextFilter, EIoSession* session) THROWS(EException); 28 | 29 | /** 30 | * {@inheritDoc} 31 | */ 32 | virtual void sessionClosed(EIoFilter::NextFilter* nextFilter, EIoSession* session) THROWS(EException); 33 | 34 | /** 35 | * {@inheritDoc} 36 | */ 37 | virtual sp messageReceived(EIoFilter::NextFilter* nextFilter, EIoSession* session, sp message) THROWS(EException); 38 | 39 | /** 40 | * {@inheritDoc} 41 | */ 42 | virtual sp messageSend(EIoFilter::NextFilter* nextFilter, EIoSession* session, sp message) THROWS(EException); 43 | 44 | /** 45 | * 46 | */ 47 | virtual EString toString(); 48 | }; 49 | 50 | } /* namespace http */ 51 | } /* namespace filter */ 52 | } /* namespace naf */ 53 | } /* namespace efc */ 54 | #endif /* EHTTPCODECFILTER_HH_ */ 55 | -------------------------------------------------------------------------------- /inc/EIoFilterAdapter.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoFilterAdapter.hh 3 | * 4 | * Created on: 2016-1-22 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EIOFILTERADAPTER_HH_ 9 | #define EIOFILTERADAPTER_HH_ 10 | 11 | #include "./EIoFilter.hh" 12 | 13 | namespace efc { 14 | namespace naf { 15 | 16 | /** 17 | * An adapter class for {@link IoFilter}. You can extend 18 | * this class and selectively override required event filter methods only. All 19 | * methods forwards events to the next filter by default. 20 | * 21 | */ 22 | 23 | class EIoFilterAdapter: virtual public EIoFilter { 24 | public: 25 | /** 26 | * {@inheritDoc} 27 | */ 28 | virtual boolean sessionCreated(EIoFilter::NextFilter* nextFilter, EIoSession* session) THROWS(EException); 29 | 30 | /** 31 | * {@inheritDoc} 32 | */ 33 | virtual void sessionClosed(EIoFilter::NextFilter* nextFilter, EIoSession* session) THROWS(EException); 34 | 35 | /** 36 | * {@inheritDoc} 37 | */ 38 | virtual sp messageReceived(EIoFilter::NextFilter* nextFilter, EIoSession* session, sp message) THROWS(EException); 39 | 40 | /** 41 | * {@inheritDoc} 42 | */ 43 | virtual sp messageSend(EIoFilter::NextFilter* nextFilter, EIoSession* session, sp message) THROWS(EException); 44 | 45 | /** 46 | * 47 | */ 48 | virtual EString toString(); 49 | }; 50 | 51 | } /* namespace naf */ 52 | } /* namespace efc */ 53 | #endif /* EIOFILTERADAPTER_HH_ */ 54 | -------------------------------------------------------------------------------- /http/source/exception.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Efc.hh" 6 | 7 | #include "../include/header_map.h" 8 | 9 | namespace efc { 10 | namespace naf { 11 | namespace Http { 12 | 13 | /** 14 | * Indicates a non-recoverable protocol error that should result in connection termination. 15 | */ 16 | class CodecProtocolException : public ERuntimeException { 17 | public: 18 | CodecProtocolException(const char *_file_, int _line_, 19 | const std::string& message) : 20 | ERuntimeException(_file_, _line_, message.c_str()) { 21 | } 22 | }; 23 | 24 | /** 25 | * Raised when a response is received on a connection that did not send a request. In practice 26 | * this can only happen on HTTP/1.1 connections. 27 | */ 28 | class PrematureResponseException : public ERuntimeException { 29 | public: 30 | PrematureResponseException(const char *_file_, int _line_, 31 | HeaderMapPtr&& headers) : 32 | ERuntimeException(_file_, _line_, ""), headers_(std::move(headers)) { 33 | } 34 | 35 | const HeaderMap& headers() { return *headers_; } 36 | 37 | private: 38 | HeaderMapPtr headers_; 39 | }; 40 | 41 | /** 42 | * Indicates a client (local) side error which should not happen. 43 | */ 44 | class CodecClientException : public ERuntimeException { 45 | public: 46 | CodecClientException(const char *_file_, int _line_, 47 | const std::string& message) : 48 | ERuntimeException(_file_, _line_, message.c_str()) { 49 | } 50 | }; 51 | 52 | } // namespace http 53 | } // namespace naf 54 | } // namespace efc 55 | -------------------------------------------------------------------------------- /http/source/macros.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace efc { 4 | namespace naf { 5 | namespace Http { 6 | 7 | /** 8 | * @return the size of a C array. 9 | */ 10 | #define ARRAY_SIZE(X) (sizeof(X) / sizeof(X[0])) 11 | 12 | /** 13 | * @return the length of a static string literal, e.g. STATIC_STRLEN("foo") == 3. 14 | */ 15 | #define STATIC_STRLEN(X) (sizeof(X) - 1) 16 | 17 | /** 18 | * Helper macros from enum to string macros. 19 | */ 20 | #define GENERATE_ENUM(X) X, 21 | #define GENERATE_STRING(X) #X, 22 | 23 | /** 24 | * Stop the compiler from complaining about an unreferenced parameter. 25 | */ 26 | #define UNREFERENCED_PARAMETER(X) ((void)(X)) 27 | 28 | /** 29 | * Construct On First Use idiom. 30 | * See https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use. 31 | */ 32 | #define CONSTRUCT_ON_FIRST_USE(type, ...) \ 33 | static const type* objectptr = new type{__VA_ARGS__}; \ 34 | return *objectptr; 35 | 36 | /** 37 | * Have a generic fall-through for different versions of C++ 38 | */ 39 | #if __cplusplus >= 201703L // C++17 and above 40 | #define FALLTHRU [[fallthrough]] 41 | #elif __cplusplus >= 201402L && __clang_major__ >= 5 // C++14 clang-5 42 | #define FALLTHRU [[fallthrough]] 43 | #elif __cplusplus >= 201103L && __GNUC__ >= 7 // C++11 gcc 7 44 | #define FALLTHRU [[gnu::fallthrough]] 45 | #else // C++11 on gcc 6, and all other cases 46 | #define FALLTHRU 47 | #endif 48 | 49 | } // http 50 | } // naf 51 | } // efc 52 | -------------------------------------------------------------------------------- /src/EHttpHandler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpHandler.cpp 3 | * 4 | * Created on: 2018-7-4 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EHttpHandler.hh" 9 | 10 | namespace efc { 11 | namespace naf { 12 | 13 | void EHttpHandler::sessionOpened(sp& session) { 14 | 15 | } 16 | 17 | void EHttpHandler::sessionClosed(sp& session) { 18 | 19 | } 20 | 21 | void EHttpHandler::service(sp& session, sp& request, sp& response) { 22 | 23 | } 24 | 25 | void EHttpHandler::doGet(sp& session, sp& request, sp& response) { 26 | 27 | } 28 | 29 | void EHttpHandler::doHead(sp& session, sp& request, sp& response) { 30 | 31 | } 32 | 33 | void EHttpHandler::doPost(sp& session, sp& request, sp& response) { 34 | 35 | } 36 | 37 | void EHttpHandler::doPut(sp& session, sp& request, sp& response) { 38 | 39 | } 40 | 41 | void EHttpHandler::doDelete(sp& session, sp& request, sp& response) { 42 | 43 | } 44 | 45 | void EHttpHandler::doOptions(sp& session, sp& request, sp& response) { 46 | 47 | } 48 | 49 | void EHttpHandler::doTrace(sp& session, sp& request, sp& response) { 50 | 51 | } 52 | 53 | void EHttpHandler::doPatch(sp& session, sp& request, sp& response) { 54 | 55 | } 56 | 57 | } /* namespace naf */ 58 | } /* namespace efc */ 59 | -------------------------------------------------------------------------------- /inc/EHttpAcceptor.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpAcceptor.hh 3 | * 4 | * Created on: 2018-6-21 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EHTTPACCEPTOR_HH_ 9 | #define EHTTPACCEPTOR_HH_ 10 | 11 | #include "./ESocketAcceptor.hh" 12 | #include "./EHttpHandler.hh" 13 | 14 | namespace efc { 15 | namespace naf { 16 | 17 | /** 18 | * {@link IoAcceptor} for http transport (HTTP&HTTP2). This class 19 | * handles incoming http based socket connections. 20 | * 21 | */ 22 | 23 | class EHttpAcceptor: public ESocketAcceptor { 24 | public: 25 | static const int WORKERS = 10; 26 | 27 | public: 28 | virtual ~EHttpAcceptor(); 29 | 30 | EHttpAcceptor(boolean rwIoDetached=false, boolean workerDetached=false); 31 | 32 | virtual void listen() THROWS(EIOException); 33 | 34 | /** 35 | * 36 | */ 37 | virtual void setHttpHandler(EHttpHandler* handler); 38 | 39 | /** 40 | * 41 | */ 42 | boolean isRWIoDetached(); 43 | 44 | /** 45 | * 46 | */ 47 | boolean isWorkerDetached(); 48 | 49 | protected: 50 | boolean rwIoDetached_; 51 | boolean workerDetached_; 52 | EHttpHandler* handler_; 53 | 54 | private: 55 | friend class ActiveStream; 56 | 57 | EFiberChannel requestChannel; 58 | 59 | /** 60 | * Override 61 | */ 62 | virtual sp newSession(EIoService *service, sp& socket); 63 | 64 | /** 65 | * Override 66 | */ 67 | virtual void onConnectionHandle(sp& session, Service* service); 68 | 69 | /** 70 | * 71 | */ 72 | void detachWriteRoutine(sp& session); 73 | 74 | /** 75 | * 76 | */ 77 | void processRequest(sp request); 78 | }; 79 | 80 | } /* namespace naf */ 81 | } /* namespace efc */ 82 | #endif /* EHTTPACCEPTOR_HH_ */ 83 | -------------------------------------------------------------------------------- /filter/http/EHttpResponse.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpResponse.hh 3 | * 4 | * Created on: 2017-4-21 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EHTTPRESPONSE_HH_ 9 | #define EHTTPRESPONSE_HH_ 10 | 11 | #include "Efc.hh" 12 | 13 | namespace efc { 14 | namespace naf { 15 | namespace filter { 16 | namespace http { 17 | 18 | class EHttpResponse: public EObject { 19 | public: 20 | EHttpResponse(void* body, int size, const char* head=NULL) { 21 | m_BodyLen = size; 22 | if (!head) { 23 | m_HttpData.appendFormat("HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\n\r\n", size); 24 | } else { 25 | m_HttpData.append(head); 26 | } 27 | m_HeadLen = m_HttpData.size(); 28 | m_HttpData.append(body, size); 29 | } 30 | EHttpResponse(EString body, const char* head=NULL) { 31 | m_BodyLen = body.length(); 32 | if (!head) { 33 | m_HttpData.appendFormat("HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\n\r\n", m_BodyLen); 34 | } else { 35 | m_HttpData.append(head); 36 | } 37 | m_HeadLen = m_HttpData.size(); 38 | m_HttpData.append(body); 39 | } 40 | char* getHttpData() { 41 | return (char*)m_HttpData.data(); 42 | } 43 | int getHttpDataLen() { 44 | return m_HttpData.size(); 45 | } 46 | char* getHeadData() { 47 | return (char*)m_HttpData.data(); 48 | } 49 | int getHeadLen() { 50 | return m_HeadLen; 51 | } 52 | char* getBodyData() { 53 | return (char*)m_HttpData.data() + m_HeadLen; 54 | } 55 | int getBodyLen() { 56 | return m_BodyLen; 57 | } 58 | private: 59 | EByteBuffer m_HttpData; 60 | int m_HeadLen; 61 | int m_BodyLen; 62 | }; 63 | 64 | } /* namespace http */ 65 | } /* namespace filter */ 66 | } /* namespace naf */ 67 | } /* namespace efc */ 68 | #endif /* EHTTPRESPONSE_HH_ */ 69 | -------------------------------------------------------------------------------- /http/include/buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../../inc/EIoBuffer.hh" 9 | 10 | namespace efc { 11 | namespace naf { 12 | namespace Http { 13 | namespace Buffer { 14 | 15 | typedef ELinkedList > LinkedBuffer; 16 | 17 | /** 18 | * A basic buffer abstraction. 19 | */ 20 | class Instance { 21 | public: 22 | virtual ~Instance() { 23 | } 24 | 25 | virtual void add(sp& buf) = 0; 26 | 27 | /** 28 | * Copy data into the buffer. 29 | * @param data supplies the data address. 30 | * @param size supplies the data size. 31 | */ 32 | virtual void add(const void* data, uint64_t size) = 0; 33 | 34 | /** 35 | * Copy a string into the buffer. 36 | * @param data supplies the string to copy. 37 | */ 38 | virtual void add(const std::string& data) = 0; 39 | 40 | /** 41 | * Drain data from the buffer. 42 | * @param size supplies the length of data to drain. 43 | */ 44 | virtual void clear() = 0; 45 | 46 | /** 47 | * @return uint64_t the total length of the buffer (not necessarily contiguous in memory). 48 | */ 49 | virtual uint64_t length() = 0; 50 | 51 | /** 52 | * Move a buffer into this buffer. As little copying is done as possible. 53 | * @param rhs supplies the buffer to move. 54 | */ 55 | virtual void move(Instance& rhs) = 0; 56 | 57 | /** 58 | * Move a portion of a buffer into this buffer. As little copying is done as possible. 59 | * @param rhs supplies the buffer to move. 60 | * @param length supplies the amount of data to move. 61 | */ 62 | virtual void move(Instance& rhs, uint64_t length) = 0; 63 | }; 64 | 65 | } // namespace buffer 66 | } // namespace http 67 | } // namespace naf 68 | } // namespace efc 69 | -------------------------------------------------------------------------------- /inc/EHttpHandler.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpHandler.hh 3 | * 4 | * Created on: 2018-7-4 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EHTTPHANDLER_HH_ 9 | #define EHTTPHANDLER_HH_ 10 | 11 | #include "./EHttpSession.hh" 12 | #include "./EHttpRequest.hh" 13 | #include "./EHttpResponse.hh" 14 | 15 | namespace efc { 16 | namespace naf { 17 | 18 | abstract class EHttpHandler: public efc::EObject { 19 | public: 20 | virtual void sessionOpened(sp& session) THROWS(EException); 21 | virtual void sessionClosed(sp& session) THROWS(EException); 22 | 23 | virtual void service(sp& session, sp& request, sp& response) THROWS(EException); 24 | 25 | virtual void doGet(sp& session, sp& request, sp& response) THROWS(EException); 26 | virtual void doHead(sp& session, sp& request, sp& response) THROWS(EException); 27 | virtual void doPost(sp& session, sp& request, sp& response) THROWS(EException); 28 | virtual void doPut(sp& session, sp& request, sp& response) THROWS(EException); 29 | virtual void doDelete(sp& session, sp& request, sp& response) THROWS(EException); 30 | virtual void doOptions(sp& session, sp& request, sp& response) THROWS(EException); 31 | virtual void doTrace(sp& session, sp& request, sp& response) THROWS(EException); 32 | virtual void doPatch(sp& session, sp& request, sp& response) THROWS(EException); 33 | }; 34 | 35 | } /* namespace naf */ 36 | } /* namespace efc */ 37 | #endif /* EHTTPHANDLER_HH_ */ 38 | -------------------------------------------------------------------------------- /test/benchmark.cpp: -------------------------------------------------------------------------------- 1 | #include "es_main.h" 2 | #include "ENaf.hh" 3 | 4 | #define LOG(fmt,...) //ESystem::out->println(fmt, ##__VA_ARGS__) 5 | 6 | static void onConnection(sp& session, ESocketAcceptor::Service* service) { 7 | LOG("onConnection: service=%s", service->toString().c_str()); 8 | 9 | sp request; 10 | try { 11 | request = dynamic_pointer_cast(session->read()); 12 | } catch (ESocketTimeoutException& e) { 13 | LOG("session read timeout."); 14 | return; 15 | } catch (EIOException& e) { 16 | LOG("session read error."); 17 | return; 18 | } 19 | if (request == null) { 20 | LOG("session client closed."); 21 | return; 22 | } 23 | 24 | // echo. 25 | #define TEST_HTTP_DATA "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nOK!" 26 | int len = strlen(TEST_HTTP_DATA); 27 | sp respone = EIoBuffer::allocate(len); 28 | respone->put(TEST_HTTP_DATA, len); 29 | respone->flip(); 30 | session->write(respone); 31 | 32 | LOG("Out of Connection."); 33 | } 34 | 35 | static void test_echo_performance() { 36 | ESocketAcceptor sa; 37 | sa.setConnectionHandler(onConnection); 38 | sa.setSoTimeout(3000); 39 | sa.setSessionIdleTime(EIdleStatus::WRITER_IDLE, 30); 40 | sa.bind("0.0.0.0", 8888); 41 | sa.listen(); 42 | } 43 | 44 | MAIN_IMPL(testnaf_benchmark) { 45 | printf("main()\n"); 46 | 47 | ESystem::init(argc, argv); 48 | ELoggerManager::init("log4e.conf"); 49 | 50 | printf("inited.\n"); 51 | 52 | int i = 0; 53 | try { 54 | boolean loop = EBoolean::parseBoolean(ESystem::getProgramArgument("loop")); 55 | do { 56 | test_echo_performance(); 57 | 58 | } while (1); 59 | } 60 | catch (EException& e) { 61 | e.printStackTrace(); 62 | } 63 | catch (...) { 64 | printf("catch all...\n"); 65 | } 66 | 67 | printf("exit...\n"); 68 | 69 | ESystem::exit(0); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /http/include/codes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace efc { 4 | namespace naf { 5 | namespace Http { 6 | 7 | /** 8 | * HTTP response codes. 9 | * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml 10 | */ 11 | enum class Code { 12 | // clang-format off 13 | Continue = 100, 14 | 15 | OK = 200, 16 | Created = 201, 17 | Accepted = 202, 18 | NonAuthoritativeInformation = 203, 19 | NoContent = 204, 20 | ResetContent = 205, 21 | PartialContent = 206, 22 | MultiStatus = 207, 23 | AlreadyReported = 208, 24 | IMUsed = 226, 25 | 26 | MultipleChoices = 300, 27 | MovedPermanently = 301, 28 | Found = 302, 29 | SeeOther = 303, 30 | NotModified = 304, 31 | UseProxy = 305, 32 | TemporaryRedirect = 307, 33 | PermanentRedirect = 308, 34 | 35 | BadRequest = 400, 36 | Unauthorized = 401, 37 | PaymentRequired = 402, 38 | Forbidden = 403, 39 | NotFound = 404, 40 | MethodNotAllowed = 405, 41 | NotAcceptable = 406, 42 | ProxyAuthenticationRequired = 407, 43 | RequestTimeout = 408, 44 | Conflict = 409, 45 | Gone = 410, 46 | LengthRequired = 411, 47 | PreconditionFailed = 412, 48 | PayloadTooLarge = 413, 49 | URITooLong = 414, 50 | UnsupportedMediaType = 415, 51 | RangeNotSatisfiable = 416, 52 | ExpectationFailed = 417, 53 | MisdirectedRequest = 421, 54 | UnprocessableEntity = 422, 55 | Locked = 423, 56 | FailedDependency = 424, 57 | UpgradeRequired = 426, 58 | PreconditionRequired = 428, 59 | TooManyRequests = 429, 60 | RequestHeaderFieldsTooLarge = 431, 61 | 62 | InternalServerError = 500, 63 | NotImplemented = 501, 64 | BadGateway = 502, 65 | ServiceUnavailable = 503, 66 | GatewayTimeout = 504, 67 | HTTPVersionNotSupported = 505, 68 | VariantAlsoNegotiates = 506, 69 | InsufficientStorage = 507, 70 | LoopDetected = 508, 71 | NotExtended = 510, 72 | NetworkAuthenticationRequired = 511 73 | // clang-format on 74 | }; 75 | 76 | } // namespace http 77 | } // namespace naf 78 | } // namespace efc 79 | -------------------------------------------------------------------------------- /http/source/buffer_impl.cc: -------------------------------------------------------------------------------- 1 | #include "./buffer_impl.h" 2 | #include "./macros.h" 3 | 4 | #include "Efc.hh" 5 | 6 | #include 7 | #include 8 | 9 | namespace efc { 10 | namespace naf { 11 | namespace Http { 12 | namespace Buffer { 13 | 14 | void OwnedImpl::add(sp& buf) { 15 | buf->flip(); 16 | buffer_.add(buf); 17 | } 18 | 19 | void OwnedImpl::add(const void* data, uint64_t size) { 20 | sp buf(EIoBuffer::allocate(size)); 21 | buf->put(data, size); 22 | add(buf); 23 | } 24 | 25 | void OwnedImpl::add(const std::string& data) { 26 | add(data.c_str(), data.length()); 27 | } 28 | 29 | void OwnedImpl::clear() { 30 | buffer_.clear(); 31 | } 32 | 33 | uint64_t OwnedImpl::length() { 34 | uint64_t len = 0; 35 | for (int i = 0; i < buffer_.size(); i++) { 36 | len += buffer_.getAt(i)->remaining(); 37 | } 38 | return len; 39 | } 40 | 41 | void OwnedImpl::move(Instance& rhs) { 42 | LinkedBuffer& that_buf = dynamic_cast(rhs).buffer_; 43 | sp iobuf; 44 | while ((iobuf = that_buf.poll()) != null) { 45 | buffer_.add(iobuf); 46 | } 47 | } 48 | 49 | void OwnedImpl::move(Instance& rhs, uint64_t length) { 50 | LinkedBuffer& that_buf = dynamic_cast(rhs).buffer_; 51 | sp iobuf; 52 | while (length > 0 && (iobuf = that_buf.peek()) != null) { 53 | if (length >= iobuf->remaining()) { 54 | buffer_.add(iobuf); 55 | that_buf.removeFirst(); 56 | length -= iobuf->remaining(); 57 | } else { 58 | add(iobuf->current(), length); 59 | iobuf->position(length); 60 | } 61 | } 62 | } 63 | 64 | OwnedImpl::OwnedImpl() : 65 | buffer_() { 66 | } 67 | 68 | OwnedImpl::OwnedImpl(const std::string& data) : 69 | OwnedImpl() { 70 | add(data); 71 | } 72 | 73 | OwnedImpl::OwnedImpl(const void* data, uint64_t size) : 74 | OwnedImpl() { 75 | add(data, size); 76 | } 77 | 78 | } // namespace buffer 79 | } // namespace http 80 | } // namespace naf 81 | } // namespace efc 82 | -------------------------------------------------------------------------------- /inc/EIoService.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoService.hh 3 | * 4 | * Created on: 2017-3-19 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EIOSERVICE_HH_ 9 | #define EIOSERVICE_HH_ 10 | 11 | #include "Efc.hh" 12 | #include "Eco.hh" 13 | #include "ELog.hh" 14 | 15 | #include "./EIoServiceStatistics.hh" 16 | #include "./EIoFilterChainBuilder.hh" 17 | 18 | namespace efc { 19 | namespace naf { 20 | 21 | /** 22 | * Base interface for all {@link IoAcceptor}s and {@link IoConnector}s 23 | * that provide I/O service and manage {@link IoSession}s. 24 | * 25 | */ 26 | 27 | interface EIoService : virtual public EObject { 28 | virtual ~EIoService() { 29 | } 30 | 31 | /** 32 | * Returns the number of all threads which are currently working by this 33 | * service. 34 | */ 35 | virtual int getWorkThreads() = 0; 36 | 37 | /** 38 | * Returns the number of all sessions which are currently managed by this 39 | * service. 40 | */ 41 | virtual int getManagedSessionCount() = 0; 42 | 43 | /** 44 | * Returns the {@link IoFilterChainBuilder} which will build the 45 | * {@link IoFilterChain} of all {@link IoSession}s which is created 46 | * by this service. 47 | * The default value is an empty {@link DefaultIoFilterChainBuilder}. 48 | */ 49 | virtual EIoFilterChainBuilder* getFilterChainBuilder() = 0; 50 | 51 | /** 52 | * Returns the IoServiceStatistics object for this service. 53 | * 54 | * @return The statistics object for this service. 55 | */ 56 | virtual EIoServiceStatistics* getStatistics() = 0; 57 | 58 | /** 59 | * Releases any resources allocated by this service. Please note that 60 | * this method might block as long as there are any sessions managed by 61 | * this service. 62 | */ 63 | virtual void dispose() = 0; 64 | 65 | /** 66 | * Returns true if and if only all resources of this processor 67 | * have been disposed. 68 | */ 69 | virtual boolean isDisposed() = 0; 70 | }; 71 | 72 | } // namespace naf 73 | } // namespace efc 74 | 75 | #endif /* EIOSERVICE_HH_ */ 76 | -------------------------------------------------------------------------------- /inc/ESubnet.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * ESubnet.hh 3 | * 4 | * Created on: 2016-5-7 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef ESUBNET_HH_ 9 | #define ESUBNET_HH_ 10 | 11 | #include "Efc.hh" 12 | 13 | namespace efc { 14 | namespace naf { 15 | 16 | /** 17 | * A IP subnet using the CIDR notation. Currently, only IP version 4 18 | * address are supported. 19 | * 20 | */ 21 | 22 | class ESubnet: public EObject { 23 | public: 24 | virtual ~ESubnet(); 25 | 26 | /** 27 | * Creates a subnet from CIDR notation. For example, the subnet 28 | * 192.168.0.0/24 would be created using the {@link InetAddress} 29 | * 192.168.0.0 and the mask 24. 30 | * @param subnet The {@link InetAddress} of the subnet 31 | * @param mask The mask 32 | */ 33 | ESubnet(EInetAddress* subnet, int mask); 34 | 35 | /** 36 | * Checks if the {@link InetAddress} is within this subnet 37 | * @param address The {@link InetAddress} to check 38 | * @return True if the address is within this subnet, false otherwise 39 | */ 40 | boolean inSubnet(EInetAddress* address); 41 | 42 | /** 43 | * {@inheritDoc} 44 | */ 45 | virtual EString toString(); 46 | 47 | /** 48 | * {@inheritDoc} 49 | */ 50 | virtual boolean equals(ESubnet* obj); 51 | 52 | private: 53 | static const int IP_MASK_V4 = 0x80000000; 54 | 55 | static const llong IP_MASK_V6 = 0x8000000000000000L; 56 | 57 | static const int BYTE_MASK = 0xFF; 58 | 59 | EInetAddress subnet; 60 | 61 | /** An int representation of a subnet for IPV4 addresses */ 62 | int subnetInt; 63 | 64 | /** An long representation of a subnet for IPV6 addresses */ 65 | long subnetLong; 66 | 67 | long subnetMask; 68 | 69 | int suffix; 70 | 71 | /** 72 | * Converts an IP address into an integer 73 | */ 74 | int toInt(EInetAddress* inetAddress); 75 | 76 | /** 77 | * Converts an IP address into a long 78 | */ 79 | long toLong(EInetAddress* inetAddress); 80 | 81 | /** 82 | * Converts an IP address to a subnet using the provided mask 83 | * 84 | * @param address 85 | * The address to convert into a subnet 86 | * @return The subnet as an integer 87 | */ 88 | long toSubnet(EInetAddress* address); 89 | }; 90 | 91 | } /* namespace naf */ 92 | } /* namespace efc */ 93 | #endif /* ESUBNET_HH_ */ 94 | -------------------------------------------------------------------------------- /src/EManagedSession.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EManagedSession.hh 3 | * 4 | * Created on: 2017-3-31 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EMANAGEDSESSION_HH_ 9 | #define EMANAGEDSESSION_HH_ 10 | 11 | #include "../inc/EIoService.hh" 12 | 13 | namespace efc { 14 | namespace naf { 15 | 16 | /** 17 | * Only thread local safe! 18 | */ 19 | 20 | class EManagedSession: public EObject { 21 | public: 22 | EManagedSession(EIoService* service) : 23 | service(service), 24 | workThreads(service->getWorkThreads()), 25 | threadSessions(workThreads) { 26 | for (int i=0; igetThreadIndex()]; 37 | ts->managedSessions->put(fd, session); 38 | ts->sessionsCounter++; 39 | } 40 | 41 | void removeSession(int fd) { 42 | EFiber* fiber = EFiber::currentFiber(); 43 | if (!fiber) { 44 | throw ENullPointerException(__FILE__, __LINE__, "Out of fiber schedule."); 45 | } 46 | ThreadSessions* ts = threadSessions[fiber->getThreadIndex()]; 47 | ts->managedSessions->remove(fd); 48 | ts->sessionsCounter--; 49 | } 50 | 51 | EHashMap* getCurrentThreadManagedSessions() { 52 | EFiber* fiber = EFiber::currentFiber(); 53 | if (!fiber) { 54 | throw ENullPointerException(__FILE__, __LINE__, "Out of fiber schedule."); 55 | } 56 | ThreadSessions* ts = threadSessions[fiber->getThreadIndex()]; 57 | return ts->managedSessions; 58 | } 59 | 60 | int getManagedSessionCount() { 61 | int count = 0; 62 | for (int i=0; isessionsCounter.value(); 64 | } 65 | return count; 66 | } 67 | 68 | private: 69 | struct ThreadSessions: public EObject { 70 | EHashMap* managedSessions; 71 | EAtomicCounter sessionsCounter; 72 | ThreadSessions(): managedSessions(new EHashMap(8192, false)) { 73 | } 74 | ~ThreadSessions() { 75 | delete managedSessions; 76 | } 77 | }; 78 | 79 | EIoService* service; 80 | int workThreads; 81 | EA threadSessions; 82 | }; 83 | 84 | } /* namespace naf */ 85 | } /* namespace efc */ 86 | #endif /* EMANAGEDSESSION_HH_ */ 87 | -------------------------------------------------------------------------------- /inc/ESocketSession.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * ESocketSession.hh 3 | * 4 | * Created on: 2016-1-19 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef ESOCKETSESSION_HH_ 9 | #define ESOCKETSESSION_HH_ 10 | 11 | #include "./EIoSession.hh" 12 | #include "./EIoBuffer.hh" 13 | #include "./EIoService.hh" 14 | #include "./EIoFilterChain.hh" 15 | 16 | namespace efc { 17 | namespace naf { 18 | 19 | class ESocketSession: public EIoSession, public enable_shared_from_this { 20 | public: 21 | virtual ~ESocketSession(); 22 | 23 | /** 24 | * 25 | * Creates a new instance of ESocketSession. 26 | * 27 | * @param service the associated IoService 28 | * @param socket the associated socket 29 | */ 30 | ESocketSession(EIoService* service, sp& socket); 31 | 32 | virtual void init(); 33 | 34 | virtual sp read(); 35 | virtual boolean write(sp message); 36 | virtual void close(); 37 | 38 | /** 39 | * {@inheritDoc} 40 | */ 41 | virtual EInetSocketAddress* getRemoteAddress(); 42 | 43 | /** 44 | * {@inheritDoc} 45 | */ 46 | virtual EInetSocketAddress* getLocalAddress(); 47 | 48 | /** 49 | * {@inheritDoc} 50 | */ 51 | virtual boolean isSecured(); 52 | 53 | /** 54 | * 55 | */ 56 | boolean isClosed(); 57 | 58 | /** 59 | * 60 | */ 61 | sp getSocket(); 62 | 63 | /** 64 | * 65 | */ 66 | int bufferLimit() { return ioBufferLimit; } 67 | 68 | private: 69 | sp socket_; 70 | boolean closed_; 71 | 72 | sp ioBuffer; 73 | uint ioBufferLimit; 74 | }; 75 | 76 | //============================================================================= 77 | 78 | /** 79 | * Represents the type of idleness of {@link IoSession} or 80 | * {@link IoSession}. There are three types of idleness: 81 | *
    82 | *
  • {@link #READER_IDLE} - No data is coming from the remote peer.
  • 83 | *
  • {@link #WRITER_IDLE} - Session is not writing any data.
  • 84 | *
85 | *

86 | * Idle time settings are all disabled by default. You can enable them 87 | * using {@link ESocketAcceptor#setIdleTime(IdleStatus,int)}. 88 | * 89 | */ 90 | enum EIdleStatus { 91 | /** 92 | * Represents the session status that no data is coming from the remote 93 | * peer. 94 | */ 95 | READER_IDLE = 0x01, 96 | 97 | /** 98 | * Represents the session status that the session is not writing any data. 99 | */ 100 | WRITER_IDLE = 0x02 101 | }; 102 | 103 | } /* namespace naf */ 104 | } /* namespace efc */ 105 | #endif /* ESOCKETSESSION_HH_ */ 106 | -------------------------------------------------------------------------------- /http/source/linked_object.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Efc.hh" 7 | 8 | namespace efc { 9 | namespace naf { 10 | namespace Http { 11 | 12 | /** 13 | * Mixin class that allows an object contained in a unique pointer to be easily linked and unlinked 14 | * from lists. 15 | */ 16 | template class LinkedObject { 17 | public: 18 | typedef std::list> ListType; 19 | 20 | /** 21 | * @return the list iterator for the object. 22 | */ 23 | typename ListType::iterator entry() { 24 | ES_ASSERT(inserted_); 25 | return entry_; 26 | } 27 | 28 | /** 29 | * @return whether the object is currently inserted into a list. 30 | */ 31 | bool inserted() { 32 | return inserted_; 33 | } 34 | 35 | /** 36 | * Move a linked item between 2 lists. 37 | * @param list1 supplies the first list. 38 | * @param list2 supplies the second list. 39 | */ 40 | void moveBetweenLists(ListType& list1, ListType& list2) { 41 | ES_ASSERT(inserted_); 42 | ES_ASSERT(std::find(list1.begin(), list1.end(), *entry_) != list1.end()); 43 | 44 | list2.splice(list2.begin(), list1, entry_); 45 | } 46 | 47 | /** 48 | * Move an item into a linked list at the front. 49 | * @param item supplies the item to move in. 50 | * @param list supplies the list to move the item into. 51 | */ 52 | void moveIntoList(std::unique_ptr&& item, ListType& list) { 53 | ES_ASSERT(!inserted_); 54 | inserted_ = true; 55 | entry_ = list.emplace(list.begin(), std::move(item)); 56 | } 57 | 58 | /** 59 | * Move an item into a linked list at the back. 60 | * @param item supplies the item to move in. 61 | * @param list supplies the list to move the item into. 62 | */ 63 | void moveIntoListBack(std::unique_ptr&& item, ListType& list) { 64 | ES_ASSERT(!inserted_); 65 | inserted_ = true; 66 | entry_ = list.emplace(list.end(), std::move(item)); 67 | } 68 | 69 | /** 70 | * Remove this item from a list. 71 | * @param list supplies the list to remove from. This item should be in this list. 72 | */ 73 | std::unique_ptr removeFromList(ListType& list) { 74 | ES_ASSERT(inserted_); 75 | ES_ASSERT(std::find(list.begin(), list.end(), *entry_) != list.end()); 76 | 77 | std::unique_ptr removed = std::move(*entry_); 78 | list.erase(entry_); 79 | inserted_ = false; 80 | return removed; 81 | } 82 | 83 | protected: 84 | LinkedObject() : inserted_(false) {} 85 | 86 | private: 87 | typename ListType::iterator entry_; 88 | bool inserted_; // iterators do not have any "invalid" value so we need this boolean for sanity 89 | // checking. 90 | }; 91 | 92 | } // namespace http 93 | } // namespace naf 94 | } // namespace efc 95 | -------------------------------------------------------------------------------- /src/ESocketSession.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ESocketSession.cpp 3 | * 4 | * Created on: 2017-3-16 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/ESocketSession.hh" 9 | 10 | namespace efc { 11 | namespace naf { 12 | 13 | ESocketSession::~ESocketSession() { 14 | // 15 | } 16 | 17 | ESocketSession::ESocketSession(EIoService* service, sp& socket): 18 | EIoSession(service), 19 | socket_(socket), closed_(false), 20 | ioBufferLimit(ES_MAX(socket_->getReceiveBufferSize(), 512)) { 21 | } 22 | 23 | void ESocketSession::init() { 24 | // 25 | } 26 | 27 | sp ESocketSession::read() { 28 | if (ioBuffer == null) { 29 | ioBuffer = EIoBuffer::allocate(ioBufferLimit); 30 | } 31 | 32 | EInputStream* is = socket_->getInputStream(); 33 | 34 | // try it for packet splicing. 35 | sp out = filterChain->fireMessageReceived(null); 36 | if (out != null) { 37 | return out; 38 | } 39 | 40 | // else read next. 41 | 42 | RESUME: 43 | ioBuffer->clear(); 44 | int n = is->read(ioBuffer->current(), ioBuffer->limit()); 45 | if (n > 0) { 46 | ioBuffer->position(n); 47 | ioBuffer->flip(); 48 | 49 | // on session message received. 50 | out = filterChain->fireMessageReceived(ioBuffer); 51 | if (out == null) { 52 | goto RESUME; 53 | } 54 | return out; 55 | } 56 | 57 | if (n == -1) { // EOF 58 | return null; 59 | } 60 | 61 | throw EIOException(__FILE__, __LINE__, "socket session read."); 62 | } 63 | 64 | boolean ESocketSession::write(sp message) { 65 | EOutputStream* os = socket_->getOutputStream(); 66 | 67 | // on session message send. 68 | sp out = filterChain->fireMessageSend(message); 69 | 70 | sp ib = dynamic_pointer_cast(out); 71 | if (ib != null) { 72 | os->write(ib->current(), ib->remaining()); 73 | return true; 74 | } 75 | 76 | sp file = dynamic_pointer_cast(out); 77 | if (file != null) { 78 | socket_->sendfile(file.get()); 79 | return true; 80 | } 81 | 82 | return false; 83 | } 84 | 85 | void ESocketSession::close() { 86 | if (!closed_) { 87 | filterChain->fireSessionClosed(); 88 | socket_->close(); 89 | closed_ = true; 90 | } 91 | } 92 | 93 | EInetSocketAddress* ESocketSession::getRemoteAddress() { 94 | return socket_->getRemoteSocketAddress(); 95 | } 96 | 97 | EInetSocketAddress* ESocketSession::getLocalAddress() { 98 | return socket_->getLocalSocketAddress(); 99 | } 100 | 101 | boolean ESocketSession::isSecured() { 102 | return dynamic_pointer_cast(socket_) != null; 103 | } 104 | 105 | boolean ESocketSession::isClosed() { 106 | return closed_; 107 | } 108 | 109 | sp ESocketSession::getSocket() { 110 | return socket_; 111 | } 112 | 113 | } /* namespace naf */ 114 | } /* namespace efc */ 115 | -------------------------------------------------------------------------------- /inc/EHttpSession.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpSession.hh 3 | * 4 | * Created on: 2018-6-21 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EHTTPSESSION_HH_ 9 | #define EHTTPSESSION_HH_ 10 | 11 | #include "./ESocketSession.hh" 12 | #include "./EHttpRequest.hh" 13 | #include "./EHttpResponse.hh" 14 | 15 | #include "../http/source/http1/codec_impl.h" 16 | #include "../http/source/http2/codec_impl.h" 17 | 18 | namespace efc { 19 | namespace naf { 20 | 21 | using namespace Http; 22 | 23 | class ActiveStream: public EObject, 24 | public Http::StreamDecoder, 25 | public Http::StreamEncoder { 26 | public: 27 | ActiveStream(EHttpSession* session, Http::StreamEncoder& encoder): session(session), response_encoder(&encoder) {} 28 | virtual ~ActiveStream() {} 29 | 30 | sp getHttpSession(); 31 | 32 | // Http::StreamDecoder 33 | virtual void decode100ContinueHeaders(HeaderMapPtr&& headers); 34 | virtual void decodeHeaders(HeaderMapPtr&& headers, bool end_stream); 35 | virtual void decodeData(Buffer::Instance& data, bool end_stream); 36 | virtual void decodeTrailers(HeaderMapPtr&& trailers); 37 | 38 | // Http::StreamEncoder 39 | virtual void encode100ContinueHeaders(const HeaderMap& headers); 40 | virtual void encodeHeaders(const HeaderMap& headers, bool end_stream); 41 | virtual void encodeData(Buffer::Instance& data, bool end_stream); 42 | virtual void encodeTrailers(const HeaderMap& trailers); 43 | 44 | private: 45 | EHttpSession* session; 46 | Http::StreamEncoder* response_encoder; 47 | 48 | sp request; 49 | sp response; 50 | }; 51 | 52 | //============================================================================= 53 | 54 | 55 | /** 56 | * 57 | */ 58 | 59 | class EHttpAcceptor; 60 | 61 | class EHttpSession: public ESocketSession, public Http::ServerConnectionCallbacks { 62 | public: 63 | virtual ~EHttpSession(); 64 | 65 | /** 66 | * 67 | * Creates a new instance of EHttpSession. 68 | * 69 | * @param service the associated IoService 70 | * @param socket the associated socket 71 | */ 72 | EHttpSession(EIoService* service, sp& socket); 73 | 74 | EHttpAcceptor* getHttpAcceptor(); 75 | 76 | virtual void init(); 77 | virtual sp read(); 78 | virtual boolean write(sp message); 79 | virtual void close(); 80 | 81 | protected: 82 | friend class EHttpAcceptor; 83 | 84 | EFiberChannel responseChannel; 85 | 86 | protected: 87 | virtual Http::StreamDecoder& newStream(Http::StreamEncoder& response_encoder); 88 | 89 | virtual void onGoAway(); 90 | 91 | EHttpAcceptor* acceptor; 92 | 93 | ELinkedList streams_; 94 | 95 | 96 | boolean isFirstRequest; 97 | sp firstRequestBuffer; 98 | 99 | Http::ServerConnectionPtr codec_; 100 | 101 | Http::Http1Settings hs1; 102 | Http::Http2Settings hs2; 103 | }; 104 | 105 | } /* namespace naf */ 106 | } /* namespace efc */ 107 | #endif /* EHTTPSESSION_HH_ */ 108 | -------------------------------------------------------------------------------- /src/EIoSession.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoSession.cpp 3 | * 4 | * Created on: 2017-3-16 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EIoSession.hh" 9 | #include "../inc/EIoService.hh" 10 | #include "../inc/EIoFilterChainBuilder.hh" 11 | 12 | namespace efc { 13 | namespace naf { 14 | 15 | long EIoSession::idGenerator = 0; 16 | 17 | EIoSession::~EIoSession() { 18 | delete filterChain; 19 | } 20 | 21 | EIoSession::EIoSession(EIoService* service): 22 | service(service), 23 | creationTime(0), 24 | lastReadTime(0), 25 | lastWriteTime(0), 26 | sessionId(idGenerator++) { 27 | 28 | // Initialize all the Session counters to the current time 29 | llong currentTime = ESystem::currentTimeMillis(); 30 | 31 | creationTime = currentTime; 32 | // lastThroughputCalculationTime = currentTime; 33 | lastReadTime = currentTime; 34 | lastWriteTime = currentTime; 35 | // lastIdleTimeForBoth = currentTime; 36 | // lastIdleTimeForRead = currentTime; 37 | // lastIdleTimeForWrite = currentTime; 38 | 39 | filterChain = new EIoFilterChain(this); 40 | 41 | // Build the filter chain of this session. 42 | EIoFilterChainBuilder* chainBuilder = getService()->getFilterChainBuilder(); 43 | chainBuilder->buildFilterChain(filterChain); 44 | } 45 | 46 | long EIoSession::getId() { 47 | return sessionId; 48 | } 49 | 50 | EIoService* EIoSession::getService() { 51 | return service; 52 | } 53 | 54 | EIoFilterChain* EIoSession::getFilterChain() { 55 | return filterChain; 56 | } 57 | 58 | llong EIoSession::getCreationTime() { 59 | return creationTime; 60 | } 61 | 62 | llong EIoSession::getLastIoTime() { 63 | return ES_MAX(lastReadTime, lastWriteTime); 64 | } 65 | 66 | llong EIoSession::getLastReadTime() { 67 | return lastReadTime; 68 | } 69 | 70 | llong EIoSession::getLastWriteTime() { 71 | return lastWriteTime; 72 | } 73 | 74 | void EIoSession::increaseReadBytes(long increment, llong currentTime) { 75 | if (increment <= 0) { 76 | return; 77 | } 78 | 79 | readBytes += increment; 80 | lastReadTime = currentTime; 81 | 82 | service->getStatistics()->increaseReadBytes(increment, currentTime); 83 | } 84 | 85 | void EIoSession::increaseReadMessages(llong currentTime) { 86 | readMessages++; 87 | lastReadTime = currentTime; 88 | 89 | service->getStatistics()->increaseReadMessages(currentTime); 90 | } 91 | 92 | void EIoSession::increaseWrittenBytes(int increment, llong currentTime) { 93 | if (increment <= 0) { 94 | return; 95 | } 96 | 97 | writtenBytes += increment; 98 | lastWriteTime = currentTime; 99 | 100 | service->getStatistics()->increaseWrittenBytes(increment, currentTime); 101 | } 102 | 103 | void EIoSession::increaseWrittenMessages(llong currentTime) { 104 | writtenMessages++; 105 | lastWriteTime = currentTime; 106 | 107 | service->getStatistics()->increaseWrittenMessages(currentTime); 108 | } 109 | 110 | EObject* EIoSession::attach(EObject* ob) { 111 | return attachment_.getAndSet(ob); 112 | } 113 | 114 | EObject* EIoSession::attachment() { 115 | return attachment_.get(); 116 | } 117 | 118 | } /* namespace naf */ 119 | } /* namespace efc */ 120 | -------------------------------------------------------------------------------- /filter/http/EHttpCodecFilter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpCodecFilter.cpp 3 | * 4 | * Created on: 2017-4-7 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "./EHttpCodecFilter.hh" 9 | #include "./EHttpRequest.hh" 10 | #include "./EHttpResponse.hh" 11 | 12 | namespace efc { 13 | namespace naf { 14 | namespace filter { 15 | namespace http { 16 | 17 | static const char* SESSION_CACHE_DATA = "session_cache_data"; 18 | 19 | boolean EHttpCodecFilter::sessionCreated(EIoFilter::NextFilter* nextFilter, 20 | EIoSession* session) { 21 | return nextFilter->sessionCreated(session); 22 | } 23 | 24 | void EHttpCodecFilter::sessionClosed(EIoFilter::NextFilter* nextFilter, 25 | EIoSession* session) { 26 | nextFilter->sessionClosed(session); 27 | } 28 | 29 | sp EHttpCodecFilter::messageReceived(EIoFilter::NextFilter* nextFilter, 30 | EIoSession* session, sp message) { 31 | 32 | sp buf = dynamic_pointer_cast(message); 33 | 34 | llong key = (llong)SESSION_CACHE_DATA; 35 | sp cache = dynamic_pointer_cast(session->attributes.get(key)); 36 | 37 | if (buf == null && (cache == null || cache->size() == 0)) { 38 | return nextFilter->messageReceived(session, null); 39 | } 40 | 41 | if (cache == null) { 42 | cache = new EByteBuffer(buf->limit(), 64); 43 | session->attributes.put(key, cache); 44 | } 45 | 46 | if (buf != null) { 47 | if (cache->size() + buf->limit() > MAX_HTTP_SIZE) { 48 | throw EOUTOFMEMORYERROR; 49 | } else { 50 | cache->append(buf->current(), buf->limit()); 51 | } 52 | } 53 | 54 | sp out; 55 | 56 | int hlen, blen, httplen; 57 | httplen = hlen = blen = 0; 58 | 59 | char* prnrn = eso_strnstr((char*)cache->data(), cache->size(), "\r\n\r\n"); 60 | if (prnrn > 0) { 61 | hlen = prnrn + 4 - (char*)cache->data(); 62 | 63 | char* plen = eso_strncasestr((char*)cache->data(), hlen, "Content-Length:"); 64 | if (plen) { 65 | plen += 15; 66 | char* plen2 = eso_strstr(plen, "\r\n"); 67 | EString lenstr(plen, 0, plen2-plen); 68 | blen = EInteger::parseInt(lenstr.trim().c_str()); 69 | 70 | httplen = hlen + blen; 71 | } else { 72 | httplen = hlen; 73 | } 74 | 75 | if (cache->size() >= httplen) { 76 | out = new EHttpRequest(cache->data(), hlen, blen); 77 | cache->erase(0, httplen); 78 | } 79 | } 80 | 81 | return nextFilter->messageReceived(session, out); 82 | } 83 | 84 | sp EHttpCodecFilter::messageSend(EIoFilter::NextFilter* nextFilter, 85 | EIoSession* session, sp message) { 86 | sp response = dynamic_pointer_cast(message); 87 | if (response != null) { 88 | sp out = EIoBuffer::allocate(response->getHttpDataLen()); 89 | out->put(response->getHttpData(), response->getHttpDataLen()); 90 | out->flip(); 91 | message = out; 92 | } 93 | return nextFilter->messageSend(session, message); 94 | } 95 | 96 | EString EHttpCodecFilter::toString() { 97 | return "EHttpCodecFilter"; 98 | } 99 | 100 | } /* namespace http */ 101 | } /* namespace filter */ 102 | } /* namespace naf */ 103 | } /* namespace efc */ 104 | -------------------------------------------------------------------------------- /inc/EBlacklistFilter.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EBlacklistFilter.hh 3 | * 4 | * Created on: 2016-5-7 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EBLACKLISTFILTER_HH_ 9 | #define EBLACKLISTFILTER_HH_ 10 | 11 | #include "ELog.hh" 12 | 13 | #include "./EIoFilterAdapter.hh" 14 | #include "./ESubnet.hh" 15 | 16 | namespace efc { 17 | namespace naf { 18 | 19 | /** 20 | * A {@link IoFilter} which blocks connections from blacklisted remote 21 | * address. 22 | * 23 | */ 24 | 25 | class EBlacklistFilter: public EIoFilterAdapter { 26 | public: 27 | /** 28 | * Sets the addresses to be blacklisted. 29 | * 30 | * NOTE: this call will remove any previously blacklisted addresses. 31 | * 32 | * @param addresses an array of addresses to be blacklisted. 33 | */ 34 | EBlacklistFilter* setBlacklist(EA* addresses); 35 | 36 | /** 37 | * Sets the subnets to be blacklisted. 38 | * 39 | * NOTE: this call will remove any previously blacklisted subnets. 40 | * 41 | * @param subnets an array of subnets to be blacklisted. 42 | */ 43 | EBlacklistFilter* setSubnetBlacklist(EA* subnets); 44 | 45 | /** 46 | * Sets the addresses to be blacklisted. 47 | * 48 | * NOTE: this call will remove any previously blacklisted addresses. 49 | * 50 | * @param addresses a collection of InetAddress objects representing the 51 | * addresses to be blacklisted. 52 | * @throws IllegalArgumentException if the specified collections contains 53 | * non-{@link InetAddress} objects. 54 | */ 55 | EBlacklistFilter* setBlacklist(EIterable* addresses); 56 | 57 | /** 58 | * Sets the subnets to be blacklisted. 59 | * 60 | * NOTE: this call will remove any previously blacklisted subnets. 61 | * 62 | * @param subnets an array of subnets to be blacklisted. 63 | */ 64 | EBlacklistFilter* setSubnetBlacklist(EIterable* subnets); 65 | 66 | /** 67 | * Blocks the specified endpoint. 68 | * 69 | * @param address The address to block 70 | */ 71 | EBlacklistFilter* block(EInetAddress* address); 72 | EBlacklistFilter* block(const char* hostname); 73 | 74 | /** 75 | * Blocks the specified subnet. 76 | * 77 | * @param subnet The subnet to block 78 | */ 79 | EBlacklistFilter* block(ESubnet* subnet); 80 | 81 | /** 82 | * Unblocks the specified endpoint. 83 | * 84 | * @param address The address to unblock 85 | */ 86 | EBlacklistFilter* unblock(EInetAddress* address); 87 | EBlacklistFilter* unblock(const char* hostname); 88 | 89 | /** 90 | * Unblocks the specified subnet. 91 | * 92 | * @param subnet The subnet to unblock 93 | */ 94 | EBlacklistFilter* unblock(ESubnet* subnet); 95 | 96 | /** 97 | * {@inheritDoc} 98 | */ 99 | virtual boolean sessionCreated(EIoFilter::NextFilter* nextFilter, EIoSession* session) THROWS(EException); 100 | 101 | private: 102 | static sp LOGGER;// = LoggerFactory.getLogger(BlacklistFilter.class); 103 | 104 | /** The list of blocked addresses */ 105 | ECopyOnWriteArrayList blacklist; 106 | 107 | boolean isBlocked(EIoSession* session); 108 | }; 109 | 110 | } /* namespace naf */ 111 | } /* namespace efc */ 112 | #endif /* EBLACKLISTFILTER_HH_ */ 113 | -------------------------------------------------------------------------------- /inc/EWhitelistFilter.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EWhitelistFilter.hh 3 | * 4 | * Created on: 2016-5-7 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EWHITELISTFILTER_HH_ 9 | #define EWHITELISTFILTER_HH_ 10 | 11 | #include "ELog.hh" 12 | 13 | #include "./EIoFilterAdapter.hh" 14 | #include "./ESubnet.hh" 15 | 16 | namespace efc { 17 | namespace naf { 18 | 19 | /** 20 | * A {@link IoFilter} which allows connections from whitelisted remote 21 | * address. 22 | * 23 | * @see: BlacklistFilter.java 24 | */ 25 | 26 | class EWhitelistFilter: public EIoFilterAdapter { 27 | public: 28 | /** 29 | * Sets the addresses to be whitelisted. 30 | * 31 | * NOTE: this call will remove any previously whitelisted addresses. 32 | * 33 | * @param addresses an array of addresses to be whitelisted. 34 | */ 35 | EWhitelistFilter* setWhitelist(EA* addresses); 36 | 37 | /** 38 | * Sets the subnets to be whitelisted. 39 | * 40 | * NOTE: this call will remove any previously whitelisted subnets. 41 | * 42 | * @param subnets an array of subnets to be whitelisted. 43 | */ 44 | EWhitelistFilter* setSubnetWhitelist(EA* subnets); 45 | 46 | /** 47 | * Sets the addresses to be whitelisted. 48 | * 49 | * NOTE: this call will remove any previously whitelisted addresses. 50 | * 51 | * @param addresses a collection of InetAddress objects representing the 52 | * addresses to be whitelisted. 53 | * @throws IllegalArgumentException if the specified collections contains 54 | * non-{@link InetAddress} objects. 55 | */ 56 | EWhitelistFilter* setWhitelist(EIterable* addresses); 57 | 58 | /** 59 | * Sets the subnets to be whitelisted. 60 | * 61 | * NOTE: this call will remove any previously whitelisted subnets. 62 | * 63 | * @param subnets an array of subnets to be whitelisted. 64 | */ 65 | EWhitelistFilter* setSubnetWhitelist(EIterable* subnets); 66 | 67 | /** 68 | * Allows the specified endpoint. 69 | * 70 | * @param address The address to allow 71 | */ 72 | EWhitelistFilter* allow(EInetAddress* address); 73 | EWhitelistFilter* allow(const char* hostname); 74 | 75 | /** 76 | * Allows the specified subnet. 77 | * 78 | * @param subnet The subnet to allow 79 | */ 80 | EWhitelistFilter* allow(ESubnet* subnet); 81 | 82 | /** 83 | * Disallows the specified endpoint. 84 | * 85 | * @param address The address to disallow 86 | */ 87 | EWhitelistFilter* disallow(EInetAddress* address); 88 | EWhitelistFilter* disallow(const char* hostname); 89 | 90 | /** 91 | * Disallows the specified subnet. 92 | * 93 | * @param subnet The subnet to disallow 94 | */ 95 | EWhitelistFilter* disallow(ESubnet* subnet); 96 | 97 | /** 98 | * {@inheritDoc} 99 | */ 100 | virtual boolean sessionCreated(EIoFilter::NextFilter* nextFilter, EIoSession* session) THROWS(EException); 101 | 102 | private: 103 | static sp LOGGER;// = LoggerFactory.getLogger(WhitelistFilter.class); 104 | 105 | /** The list of allowed addresses */ 106 | ECopyOnWriteArrayList whitelist; 107 | 108 | boolean isAllowed(EIoSession* session); 109 | }; 110 | 111 | } /* namespace naf */ 112 | } /* namespace efc */ 113 | #endif /* EWHITELISTFILTER_HH_ */ 114 | -------------------------------------------------------------------------------- /test/Makefile_unix: -------------------------------------------------------------------------------- 1 | ################OPTION################### 2 | # release or debug 3 | VERTYPE=RELEASE 4 | 5 | KERNEL:=$(shell uname) 6 | LIBDIR = linux 7 | CPPSTD = c++11 8 | 9 | ARCH:=$(shell uname -m) 10 | RC:=$(ARCH) 11 | BIT32:=i686 12 | BIT64:=x86_64 13 | 14 | $(info KERNEL=$(KERNEL)) 15 | $(info ARCH=$(ARCH)) 16 | 17 | ifeq ($(KERNEL),Darwin) 18 | LIBDIR = osx 19 | endif 20 | 21 | ifeq ($(RC),$(BIT32)) 22 | SHAREDLIB = -lefc32 -leso32 -lrt -lm -ldl -lpthread -lssl -lcrypto -lnghttp2 23 | else 24 | SHAREDLIB = -lefc64 -leso64 -liconv -ldl -lpthread -lssl -lcrypto -lnghttp2 25 | endif 26 | 27 | ifeq ($(VERTYPE), RELEASE) 28 | CCOMPILEOPTION = -c -g -O2 -D__MAIN__ 29 | CPPCOMPILEOPTION = -std=$(CPPSTD) -c -g -O2 -fpermissive -D__MAIN__ 30 | TESTNAF = testnaf 31 | BENCHMARK = benchmark 32 | HTTPSERVER = httpserver 33 | else 34 | CCOMPILEOPTION = -c -g -D__MAIN__ 35 | CPPCOMPILEOPTION = -std=$(CPPSTD) -c -g -fpermissive -DDEBUG -D__MAIN__ 36 | TESTNAF = testnaf_d 37 | BENCHMARK = benchmark_d 38 | HTTPSERVER = httpserver_d 39 | endif 40 | 41 | CCOMPILE = gcc 42 | CPPCOMPILE = g++ 43 | INCLUDEDIR = \ 44 | -I../../efc \ 45 | -I../../eco \ 46 | -I../../eco/inc \ 47 | -I../../elog \ 48 | -I../../elog/inc \ 49 | -I../../CxxJDK/efc \ 50 | -I../../CxxFiber \ 51 | -I../../CxxFiber/inc \ 52 | -I../../CxxLog4j \ 53 | -I../../CxxLog4j/inc \ 54 | -I../filter/http \ 55 | -I../inc \ 56 | -I../ \ 57 | -I/usr/local/Cellar/openssl/1.0.2g/include \ 58 | -I/usr/local/openssl/include \ 59 | 60 | LINK = g++ 61 | LINKOPTION = -std=$(CPPSTD) -g 62 | LIBDIRS = -L../../efc/lib/$(LIBDIR) -L../../CxxJDK/lib/$(LIBDIR) -L/usr/local/openssl/lib/ 63 | APPENDLIB = 64 | 65 | BASE_SRC += $(sort $(wildcard ../src/*.cpp ../filter/http/*.cpp ../http_parser/*.c ../http/source/*.cc ../http/source/http1/*.cc ../http/source/http2/*.cc)) 66 | BASE_SRC += $(sort $(wildcard ../../eco/src/*.cpp ../../eco/src/*.c ../../CxxFiber/src/*.cpp ../../CxxFiber/src/*.c)) 67 | BASE_SRC += $(sort $(wildcard ../../elog/src/*.cpp ./../CxxLog4j/src/*.cpp)) 68 | BASE_OBJS += $(patsubst %.cc,%.o, $(patsubst %.cpp,%.o, $(patsubst %.c,%.o, $(BASE_SRC)))) 69 | 70 | TESTNAF_OBJS = testnaf.o \ 71 | 72 | BENCHMARK_OBJS = benchmark.o \ 73 | 74 | HTTPSERVER_OBJS = httpserver.o \ 75 | 76 | $(TESTNAF): $(BASE_OBJS) $(TESTNAF_OBJS) $(APPENDLIB) 77 | $(LINK) $(LINKOPTION) -o $(TESTNAF) $(LIBDIRS) $(BASE_OBJS) $(TESTNAF_OBJS) $(SHAREDLIB) $(APPENDLIB) 78 | 79 | $(HTTPSERVER): $(BASE_OBJS) $(HTTPSERVER_OBJS) $(APPENDLIB) 80 | $(LINK) $(LINKOPTION) -o $(HTTPSERVER) $(LIBDIRS) $(BASE_OBJS) $(HTTPSERVER_OBJS) $(SHAREDLIB) $(APPENDLIB) 81 | 82 | $(BENCHMARK): $(BASE_OBJS) $(BENCHMARK_OBJS) $(APPENDLIB) 83 | $(LINK) $(LINKOPTION) -o $(BENCHMARK) $(LIBDIRS) $(BASE_OBJS) $(BENCHMARK_OBJS) $(SHAREDLIB) $(APPENDLIB) 84 | 85 | clean: 86 | rm -f $(BASE_OBJS) $(TESTNAF_OBJS) $(BENCHMARK) 87 | 88 | all: clean $(TESTNAF) $(BENCHMARK) clean 89 | .PRECIOUS:%.cpp %.c %.cc 90 | .SUFFIXES: 91 | .SUFFIXES: .c .o .cpp .cc 92 | 93 | .cpp.o: 94 | $(CPPCOMPILE) -c -o $*.o $(CPPCOMPILEOPTION) $(INCLUDEDIR) $*.cpp 95 | 96 | .c.o: 97 | $(CCOMPILE) -c -o $*.o $(CCOMPILEOPTION) $(INCLUDEDIR) $*.c 98 | 99 | .cc.o: 100 | $(CPPCOMPILE) -c -o $*.o $(CPPCOMPILEOPTION) $(INCLUDEDIR) $*.cc 101 | -------------------------------------------------------------------------------- /src/ESubnet.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ESubnet.cpp 3 | * 4 | * Created on: 2016-5-7 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/ESubnet.hh" 9 | 10 | namespace efc { 11 | namespace naf { 12 | 13 | // Warning: Now only support IPV4 address. 14 | 15 | ESubnet::~ESubnet() { 16 | 17 | } 18 | 19 | ESubnet::ESubnet(EInetAddress* subnet, int mask) { 20 | /* @see: 21 | if (subnet == null) { 22 | throw new IllegalArgumentException("Subnet address can not be null"); 23 | } 24 | 25 | if (!(subnet instanceof Inet4Address) && !(subnet instanceof Inet6Address)) { 26 | throw new IllegalArgumentException("Only IPv4 and IPV6 supported"); 27 | } 28 | 29 | if (subnet instanceof Inet4Address) { 30 | // IPV4 address 31 | if ((mask < 0) || (mask > 32)) { 32 | throw new IllegalArgumentException("Mask has to be an integer between 0 and 32 for an IPV4 address"); 33 | } else { 34 | this.subnet = subnet; 35 | subnetInt = toInt(subnet); 36 | this.suffix = mask; 37 | 38 | // binary mask for this subnet 39 | this.subnetMask = IP_MASK_V4 >> (mask - 1); 40 | } 41 | } else { 42 | // IPV6 address 43 | if ((mask < 0) || (mask > 128)) { 44 | throw new IllegalArgumentException("Mask has to be an integer between 0 and 128 for an IPV6 address"); 45 | } else { 46 | this.subnet = subnet; 47 | subnetLong = toLong(subnet); 48 | this.suffix = mask; 49 | 50 | // binary mask for this subnet 51 | this.subnetMask = IP_MASK_V6 >> (mask - 1); 52 | } 53 | } 54 | */ 55 | 56 | if (subnet == null) { 57 | throw EIllegalArgumentException(__FILE__, __LINE__, "Subnet address can not be null"); 58 | } 59 | 60 | // IPV4 address 61 | if ((mask < 0) || (mask > 32)) { 62 | throw EIllegalArgumentException(__FILE__, __LINE__, "Mask has to be an integer between 0 and 32 for an IPV4 address"); 63 | } else { 64 | this->subnet = *subnet; 65 | subnetInt = toInt(subnet); 66 | this->suffix = mask; 67 | 68 | // binary mask for this subnet 69 | this->subnetMask = IP_MASK_V4 >> (mask - 1); 70 | } 71 | } 72 | 73 | boolean ESubnet::inSubnet(EInetAddress* address) { 74 | /* @see: 75 | if (address.isAnyLocalAddress()) { 76 | return true; 77 | } 78 | 79 | if (address instanceof Inet4Address) { 80 | return (int) toSubnet(address) == subnetInt; 81 | } else { 82 | return toSubnet(address) == subnetLong; 83 | } 84 | */ 85 | 86 | if (!address) return false; 87 | 88 | if (address->isAnyLocalAddress()) { 89 | return true; 90 | } 91 | 92 | return (int) toSubnet(address) == subnetInt; 93 | } 94 | 95 | EString ESubnet::toString() { 96 | return subnet.getHostAddress() + "/" + suffix; 97 | } 98 | 99 | boolean ESubnet::equals(ESubnet* other) { 100 | if (!other) return false; 101 | 102 | return other->subnetInt == subnetInt && other->suffix == suffix; 103 | } 104 | 105 | int ESubnet::toInt(EInetAddress* inetAddress) { 106 | /* @see: 107 | byte[] address = inetAddress.getAddress(); 108 | int result = 0; 109 | 110 | for (int i = 0; i < address.length; i++) { 111 | result <<= 8; 112 | result |= address[i] & BYTE_MASK; 113 | } 114 | 115 | return result; 116 | */ 117 | return inetAddress->getAddress(); 118 | } 119 | 120 | long ESubnet::toLong(EInetAddress* inetAddress) { 121 | return inetAddress->getAddress(); 122 | } 123 | 124 | long ESubnet::toSubnet(EInetAddress* address) { 125 | /* @see: 126 | if (address instanceof Inet4Address) { 127 | return toInt(address) & (int) subnetMask; 128 | } else { 129 | return toLong(address) & subnetMask; 130 | } 131 | */ 132 | 133 | return address->getAddress() & (int) subnetMask; 134 | } 135 | 136 | } /* namespace naf */ 137 | } /* namespace efc */ 138 | -------------------------------------------------------------------------------- /inc/EIoFilter.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoFilter.hh 3 | * 4 | * Created on: 2017-3-16 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EIOFILTER_HH_ 9 | #define EIOFILTER_HH_ 10 | 11 | #include "./EIoSession.hh" 12 | 13 | namespace efc { 14 | namespace naf { 15 | 16 | interface EIoFilterChain; 17 | 18 | interface EIoFilter: virtual public EObject { 19 | /** 20 | * Represents the next {@link IoFilter} in {@link IoFilterChain}. 21 | */ 22 | interface NextFilter { 23 | virtual ~NextFilter() { 24 | } 25 | 26 | /** 27 | * Forwards sessionCreated event to next filter. 28 | * 29 | * @param session The {@link IoSession} which has to process this invocation 30 | */ 31 | virtual boolean sessionCreated(EIoSession* session) = 0; 32 | 33 | /** 34 | * Forwards sessionClosed event to next filter. 35 | * 36 | * @param session The {@link IoSession} which has to process this invocation 37 | */ 38 | virtual void sessionClosed(EIoSession* session) = 0; 39 | 40 | /** 41 | * Forwards messageReceived event to next filter. 42 | * 43 | * @param session The {@link IoSession} which has to process this invocation 44 | * @param message The received message 45 | */ 46 | virtual sp messageReceived(EIoSession* session, sp message) = 0; 47 | 48 | /** 49 | * Forwards messageSend event to next filter. 50 | * 51 | * @param session The {@link IoSession} which has to process this invocation 52 | * @param data The message data to write 53 | * @param size The message data size 54 | */ 55 | virtual sp messageSend(EIoSession* session, sp message) = 0; 56 | }; 57 | 58 | virtual ~EIoFilter() { 59 | } 60 | 61 | /** 62 | * Filters {@link IoHandler#sessionCreated(IoSession)} event. 63 | * 64 | * @param nextFilter 65 | * the {@link NextFilter} for this filter. You can reuse this 66 | * object until this filter is removed from the chain. 67 | * @param session The {@link IoSession} which has received this event 68 | * @throws Exception If an error occurred while processing the event 69 | */ 70 | virtual boolean sessionCreated(NextFilter* nextFilter, EIoSession* session) 71 | THROWS(EException) = 0; 72 | 73 | /** 74 | * Filters {@link IoHandler#sessionClosed(IoSession)} event. 75 | * 76 | * @param nextFilter 77 | * the {@link NextFilter} for this filter. You can reuse this 78 | * object until this filter is removed from the chain. 79 | * @param session The {@link IoSession} which has received this event 80 | * @throws Exception If an error occurred while processing the event 81 | */ 82 | virtual void sessionClosed(NextFilter* nextFilter, EIoSession* session) 83 | THROWS(EException) = 0; 84 | 85 | /** 86 | * Filters {@link IoHandler#messageReceived(IoSession,Object)} event. 87 | * 88 | * @param nextFilter 89 | * the {@link NextFilter} for this filter. You can reuse this 90 | * object until this filter is removed from the chain. 91 | * @param session The {@link IoSession} which has received this event 92 | * @param message The received message 93 | * @throws Exception If an error occurred while processing the event 94 | */ 95 | virtual sp messageReceived(NextFilter* nextFilter, EIoSession* session, 96 | sp message) THROWS(EException) = 0; 97 | 98 | /** 99 | * Filters {@link IoHandler#messageSend(IoSession,Object)} event. 100 | * 101 | * @param nextFilter 102 | * the {@link NextFilter} for this filter. You can reuse this 103 | * object until this filter is removed from the chain. 104 | * @param session The {@link IoSession} which has received this event 105 | * @param writeRequest The {@link WriteRequest} that contains the sent message 106 | * @throws Exception If an error occurred while processing the event 107 | */ 108 | virtual sp messageSend(NextFilter* nextFilter, EIoSession* session, 109 | sp message) THROWS(EException) = 0; 110 | }; 111 | 112 | } /* namespace naf */ 113 | } /* namespace efc */ 114 | #endif /* EIOFILTER_HH_ */ 115 | -------------------------------------------------------------------------------- /src/EBlacklistFilter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EBlacklistFilter.cpp 3 | * 4 | * Created on: 2016-5-7 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EBlacklistFilter.hh" 9 | 10 | namespace efc { 11 | namespace naf { 12 | 13 | sp EBlacklistFilter::LOGGER = ELoggerManager::getLogger("EBlacklistFilter"); 14 | 15 | EBlacklistFilter* EBlacklistFilter::setBlacklist(EA* addresses) { 16 | if (addresses == null) { 17 | throw EIllegalArgumentException(__FILE__, __LINE__, "addresses"); 18 | } 19 | 20 | blacklist.clear(); 21 | 22 | for (int i = 0; i < addresses->length(); i++) { 23 | EInetAddress* addr = (*addresses)[i]; 24 | block(addr); 25 | } 26 | 27 | return this; 28 | } 29 | 30 | EBlacklistFilter* EBlacklistFilter::setSubnetBlacklist(EA* subnets) { 31 | if (subnets == null) { 32 | throw EIllegalArgumentException(__FILE__, __LINE__, "Subnets must not be null"); 33 | } 34 | 35 | blacklist.clear(); 36 | 37 | for (int i = 0; i < subnets->length(); i++) { 38 | ESubnet* subnet = (*subnets)[i]; 39 | block(subnet); 40 | } 41 | 42 | return this; 43 | } 44 | 45 | EBlacklistFilter* EBlacklistFilter::setBlacklist(EIterable* addresses) { 46 | if (addresses == null) { 47 | throw EIllegalArgumentException(__FILE__, __LINE__, "addresses"); 48 | } 49 | 50 | blacklist.clear(); 51 | 52 | sp > iter = addresses->iterator(); 53 | while (iter->hasNext()) { 54 | block(iter->next()); 55 | } 56 | 57 | return this; 58 | } 59 | 60 | EBlacklistFilter* EBlacklistFilter::setSubnetBlacklist(EIterable* subnets) { 61 | if (subnets == null) { 62 | throw EIllegalArgumentException(__FILE__, __LINE__, "Subnets must not be null"); 63 | } 64 | 65 | blacklist.clear(); 66 | 67 | sp > iter = subnets->iterator(); 68 | while (iter->hasNext()) { 69 | block(iter->next()); 70 | } 71 | 72 | return this; 73 | } 74 | 75 | EBlacklistFilter* EBlacklistFilter::block(EInetAddress* address) { 76 | if (address == null) { 77 | throw EIllegalArgumentException(__FILE__, __LINE__, "Adress to block can not be null"); 78 | } 79 | 80 | blacklist.add(new ESubnet(address, 32)); 81 | 82 | return this; 83 | } 84 | 85 | EBlacklistFilter* EBlacklistFilter::block(const char* hostname) { 86 | EInetAddress address = EInetAddress::getByName(hostname); 87 | return this->block(&address); 88 | } 89 | 90 | EBlacklistFilter* EBlacklistFilter::block(ESubnet* subnet) { 91 | if (subnet == null) { 92 | throw EIllegalArgumentException(__FILE__, __LINE__, "Subnet can not be null"); 93 | } 94 | 95 | blacklist.add(new ESubnet(*subnet)); 96 | 97 | return this; 98 | } 99 | 100 | EBlacklistFilter* EBlacklistFilter::unblock(EInetAddress* address) { 101 | if (address == null) { 102 | throw EIllegalArgumentException(__FILE__, __LINE__, "Adress to unblock can not be null"); 103 | } 104 | 105 | ESubnet subnet(address, 32); 106 | blacklist.remove(&subnet); 107 | 108 | return this; 109 | } 110 | 111 | EBlacklistFilter* EBlacklistFilter::unblock(const char* hostname) { 112 | EInetAddress address = EInetAddress::getByName(hostname); 113 | return this->unblock(&address); 114 | } 115 | 116 | EBlacklistFilter* EBlacklistFilter::unblock(ESubnet* subnet) { 117 | if (subnet == null) { 118 | throw EIllegalArgumentException(__FILE__, __LINE__, "Subnet can not be null"); 119 | } 120 | 121 | blacklist.remove(subnet); 122 | 123 | return this; 124 | } 125 | 126 | boolean EBlacklistFilter::sessionCreated(EIoFilter::NextFilter* nextFilter, EIoSession* session) { 127 | if (!isBlocked(session)) { 128 | // forward if not blocked 129 | return nextFilter->sessionCreated(session); 130 | } else { 131 | EString msg = EString::formatOf( 132 | "Remote address: %s not in the blacklist; closing.", 133 | session->getRemoteAddress()->toString().c_str()); 134 | LOGGER->warn(__FILE__, __LINE__, msg.c_str()); 135 | return false; 136 | } 137 | } 138 | 139 | boolean EBlacklistFilter::isBlocked(EIoSession* session) { 140 | EInetSocketAddress* remoteAddress = session->getRemoteAddress(); 141 | 142 | //if (remoteAddress instanceof InetSocketAddress) 143 | { 144 | EInetAddress* address = remoteAddress->getAddress(); 145 | 146 | // check all subnets 147 | sp > > iter = blacklist.iterator(); 148 | while (iter->hasNext()) { 149 | sp subnet = iter->next(); 150 | if (subnet->inSubnet(address)) { 151 | return true; 152 | } 153 | } 154 | } 155 | 156 | return false; 157 | } 158 | 159 | } /* namespace naf */ 160 | } /* namespace efc */ 161 | -------------------------------------------------------------------------------- /src/EWhitelistFilter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EWhitelistFilter.cpp 3 | * 4 | * Created on: 2016-5-7 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EWhitelistFilter.hh" 9 | 10 | namespace efc { 11 | namespace naf { 12 | 13 | sp EWhitelistFilter::LOGGER = ELoggerManager::getLogger("EWhitelistFilter"); 14 | 15 | EWhitelistFilter* EWhitelistFilter::setWhitelist(EA* addresses) { 16 | if (addresses == null) { 17 | throw EIllegalArgumentException(__FILE__, __LINE__, "addresses"); 18 | } 19 | 20 | whitelist.clear(); 21 | 22 | for (int i = 0; i < addresses->length(); i++) { 23 | EInetAddress* addr = (*addresses)[i]; 24 | allow(addr); 25 | } 26 | 27 | return this; 28 | } 29 | 30 | EWhitelistFilter* EWhitelistFilter::setSubnetWhitelist(EA* subnets) { 31 | if (subnets == null) { 32 | throw EIllegalArgumentException(__FILE__, __LINE__, "Subnets must not be null"); 33 | } 34 | 35 | whitelist.clear(); 36 | 37 | for (int i = 0; i < subnets->length(); i++) { 38 | ESubnet* subnet = (*subnets)[i]; 39 | allow(subnet); 40 | } 41 | 42 | return this; 43 | } 44 | 45 | EWhitelistFilter* EWhitelistFilter::setWhitelist(EIterable* addresses) { 46 | if (addresses == null) { 47 | throw EIllegalArgumentException(__FILE__, __LINE__, "addresses"); 48 | } 49 | 50 | whitelist.clear(); 51 | 52 | sp > iter = addresses->iterator(); 53 | while (iter->hasNext()) { 54 | allow(iter->next()); 55 | } 56 | 57 | return this; 58 | } 59 | 60 | EWhitelistFilter* EWhitelistFilter::setSubnetWhitelist(EIterable* subnets) { 61 | if (subnets == null) { 62 | throw EIllegalArgumentException(__FILE__, __LINE__, "Subnets must not be null"); 63 | } 64 | 65 | whitelist.clear(); 66 | 67 | sp > iter = subnets->iterator(); 68 | while (iter->hasNext()) { 69 | allow(iter->next()); 70 | } 71 | 72 | return this; 73 | } 74 | 75 | EWhitelistFilter* EWhitelistFilter::allow(EInetAddress* address) { 76 | if (address == null) { 77 | throw EIllegalArgumentException(__FILE__, __LINE__, "Adress to allow can not be null"); 78 | } 79 | 80 | whitelist.add(new ESubnet(address, 32)); 81 | 82 | return this; 83 | } 84 | 85 | EWhitelistFilter* EWhitelistFilter::allow(const char* hostname) { 86 | EInetAddress address = EInetAddress::getByName(hostname); 87 | return this->allow(&address); 88 | } 89 | 90 | EWhitelistFilter* EWhitelistFilter::allow(ESubnet* subnet) { 91 | if (subnet == null) { 92 | throw EIllegalArgumentException(__FILE__, __LINE__, "Subnet can not be null"); 93 | } 94 | 95 | whitelist.add(new ESubnet(*subnet)); 96 | 97 | return this; 98 | } 99 | 100 | EWhitelistFilter* EWhitelistFilter::disallow(EInetAddress* address) { 101 | if (address == null) { 102 | throw EIllegalArgumentException(__FILE__, __LINE__, "Adress to disallow can not be null"); 103 | } 104 | 105 | ESubnet subnet(address, 32); 106 | whitelist.remove(&subnet); 107 | 108 | return this; 109 | } 110 | 111 | EWhitelistFilter* EWhitelistFilter::disallow(const char* hostname) { 112 | EInetAddress address = EInetAddress::getByName(hostname); 113 | return this->disallow(&address); 114 | } 115 | 116 | EWhitelistFilter* EWhitelistFilter::disallow(ESubnet* subnet) { 117 | if (subnet == null) { 118 | throw EIllegalArgumentException(__FILE__, __LINE__, "Subnet can not be null"); 119 | } 120 | 121 | whitelist.remove(subnet); 122 | 123 | return this; 124 | } 125 | 126 | boolean EWhitelistFilter::sessionCreated(EIoFilter::NextFilter* nextFilter, 127 | EIoSession* session) { 128 | if (isAllowed(session)) { 129 | // forward if allowed 130 | return nextFilter->sessionCreated(session); 131 | } else { 132 | EString msg = EString::formatOf( 133 | "Remote address: %s not in the whitelist; closing.", 134 | session->getRemoteAddress()->toString().c_str()); 135 | LOGGER->warn(__FILE__, __LINE__, msg.c_str()); 136 | return false; 137 | } 138 | } 139 | 140 | boolean EWhitelistFilter::isAllowed(EIoSession* session) { 141 | EInetSocketAddress* remoteAddress = session->getRemoteAddress(); 142 | 143 | //if (remoteAddress instanceof InetSocketAddress) 144 | { 145 | EInetAddress* address = remoteAddress->getAddress(); 146 | 147 | // check all subnets 148 | sp > > iter = whitelist.iterator(); 149 | while (iter->hasNext()) { 150 | sp subnet = iter->next(); 151 | if (subnet->inSubnet(address)) { 152 | return true; 153 | } 154 | } 155 | } 156 | 157 | return false; 158 | } 159 | 160 | } /* namespace naf */ 161 | } /* namespace efc */ 162 | -------------------------------------------------------------------------------- /http/source/codes.cc: -------------------------------------------------------------------------------- 1 | #include "./codes.h" 2 | #include "./enum_to_int.h" 3 | 4 | #include 5 | 6 | namespace efc { 7 | namespace naf { 8 | namespace Http { 9 | 10 | std::string CodeUtility::groupStringForResponseCode(Code response_code) { 11 | if (CodeUtility::is2xx(enumToInt(response_code))) { 12 | return "2xx"; 13 | } else if (CodeUtility::is3xx(enumToInt(response_code))) { 14 | return "3xx"; 15 | } else if (CodeUtility::is4xx(enumToInt(response_code))) { 16 | return "4xx"; 17 | } else if (CodeUtility::is5xx(enumToInt(response_code))) { 18 | return "5xx"; 19 | } else { 20 | return ""; 21 | } 22 | } 23 | 24 | const char* CodeUtility::toString(Code code) { 25 | // clang-format off 26 | switch (code) { 27 | // 1xx 28 | case Code::Continue: 29 | return "Continue"; 30 | 31 | // 2xx 32 | case Code::OK: 33 | return "OK"; 34 | case Code::Created: 35 | return "Created"; 36 | case Code::Accepted: 37 | return "Accepted"; 38 | case Code::NonAuthoritativeInformation: 39 | return "Non-Authoritative Information"; 40 | case Code::NoContent: 41 | return "No Content"; 42 | case Code::ResetContent: 43 | return "Reset Content"; 44 | case Code::PartialContent: 45 | return "Partial Content"; 46 | case Code::MultiStatus: 47 | return "Multi-Status"; 48 | case Code::AlreadyReported: 49 | return "Already Reported"; 50 | case Code::IMUsed: 51 | return "IM Used"; 52 | 53 | // 3xx 54 | case Code::MultipleChoices: 55 | return "Multiple Choices"; 56 | case Code::MovedPermanently: 57 | return "Moved Permanently"; 58 | case Code::Found: 59 | return "Found"; 60 | case Code::SeeOther: 61 | return "See Other"; 62 | case Code::NotModified: 63 | return "Not Modified"; 64 | case Code::UseProxy: 65 | return "Use Proxy"; 66 | case Code::TemporaryRedirect: 67 | return "Temporary Redirect"; 68 | case Code::PermanentRedirect: 69 | return "Permanent Redirect"; 70 | 71 | // 4xx 72 | case Code::BadRequest: 73 | return "Bad Request"; 74 | case Code::Unauthorized: 75 | return "Unauthorized"; 76 | case Code::PaymentRequired: 77 | return "Payment Required"; 78 | case Code::Forbidden: 79 | return "Forbidden"; 80 | case Code::NotFound: 81 | return "Not Found"; 82 | case Code::MethodNotAllowed: 83 | return "Method Not Allowed"; 84 | case Code::NotAcceptable: 85 | return "Not Acceptable"; 86 | case Code::ProxyAuthenticationRequired: 87 | return "Proxy Authentication Required"; 88 | case Code::RequestTimeout: 89 | return "Request Timeout"; 90 | case Code::Conflict: 91 | return "Conflict"; 92 | case Code::Gone: 93 | return "Gone"; 94 | case Code::LengthRequired: 95 | return "Length Required"; 96 | case Code::PreconditionFailed: 97 | return "Precondition Failed"; 98 | case Code::PayloadTooLarge: 99 | return "Payload Too Large"; 100 | case Code::URITooLong: 101 | return "URI Too Long"; 102 | case Code::UnsupportedMediaType: 103 | return "Unsupported Media Type"; 104 | case Code::RangeNotSatisfiable: 105 | return "Range Not Satisfiable"; 106 | case Code::ExpectationFailed: 107 | return "Expectation Failed"; 108 | case Code::MisdirectedRequest: 109 | return "Misdirected Request"; 110 | case Code::UnprocessableEntity: 111 | return "Unprocessable Entity"; 112 | case Code::Locked: 113 | return "Locked"; 114 | case Code::FailedDependency: 115 | return "Failed Dependency"; 116 | case Code::UpgradeRequired: 117 | return "Upgrade Required"; 118 | case Code::PreconditionRequired: 119 | return "Precondition Required"; 120 | case Code::TooManyRequests: 121 | return "Too Many Requests"; 122 | case Code::RequestHeaderFieldsTooLarge: 123 | return "Request Header Fields Too Large"; 124 | 125 | // 5xx 126 | case Code::InternalServerError: 127 | return "Internal Server Error"; 128 | case Code::NotImplemented: 129 | return "Not Implemented"; 130 | case Code::BadGateway: 131 | return "Bad Gateway"; 132 | case Code::ServiceUnavailable: 133 | return "Service Unavailable"; 134 | case Code::GatewayTimeout: 135 | return "Gateway Timeout"; 136 | case Code::HTTPVersionNotSupported: 137 | return "HTTP Version Not Supported"; 138 | case Code::VariantAlsoNegotiates: 139 | return "Variant Also Negotiates"; 140 | case Code::InsufficientStorage: 141 | return "Insufficient Storage"; 142 | case Code::LoopDetected: 143 | return "Loop Detected"; 144 | case Code::NotExtended: 145 | return "Not Extended"; 146 | case Code::NetworkAuthenticationRequired: 147 | return "Network Authentication Required"; 148 | } 149 | // clang-format on 150 | 151 | return "Unknown"; 152 | } 153 | 154 | } // namespace http 155 | } // namespace naf 156 | } // namespace efc 157 | -------------------------------------------------------------------------------- /inc/EIoFilterChainBuilder.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoFilterChainBuilder.hh 3 | * 4 | * Created on: 2017-3-16 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef NFILTERCHAINBUILDER_HH_ 9 | #define NFILTERCHAINBUILDER_HH_ 10 | 11 | #include "./EIoFilterChain.hh" 12 | 13 | namespace efc { 14 | namespace naf { 15 | 16 | /** 17 | * The default implementation of {@link IoFilterChainBuilder} which is useful 18 | * in most cases. {@link DefaultIoFilterChainBuilder} has an identical interface 19 | * with {@link IoFilter}; it contains a list of {@link IoFilter}s that you can 20 | * modify. The {@link IoFilter}s which are added to this builder will be appended 21 | * to the {@link IoFilterChain} when {@link #buildFilterChain(IoFilterChain)} is 22 | * invoked. 23 | *

24 | * However, the identical interface doesn't mean that it behaves in an exactly 25 | * same way with {@link IoFilterChain}. {@link DefaultIoFilterChainBuilder} 26 | * doesn't manage the life cycle of the {@link IoFilter}s at all, and the 27 | * existing {@link IoSession}s won't get affected by the changes in this builder. 28 | * {@link IoFilterChainBuilder}s affect only newly created {@link IoSession}s. 29 | * 30 | *

 31 |  * IoAcceptor acceptor = ...;
 32 |  * DefaultIoFilterChainBuilder builder = acceptor.getFilterChain();
 33 |  * builder.addLast( "myFilter", new MyFilter() );
 34 |  * ...
 35 |  * 
36 | * 37 | */ 38 | 39 | class EIoFilterChainBuilder: public EObject { 40 | public: 41 | virtual ~EIoFilterChainBuilder(); 42 | 43 | /** 44 | * Creates a new instance with an empty filter list. 45 | */ 46 | EIoFilterChainBuilder(); 47 | 48 | /** 49 | * Returns the {@link Entry} with the specified name in this chain. 50 | * 51 | * @param name The filter's name we are looking for 52 | * @return null if there's no such name in this chain 53 | */ 54 | EIoFilterChain::Entry* getEntry(const char* name); 55 | 56 | /** 57 | * @see IoFilterChain#getEntry(IoFilter) 58 | * 59 | * @param filter The Filter we are looking for 60 | * @return The found Entry 61 | */ 62 | EIoFilterChain::Entry* getEntry(EIoFilter* filter); 63 | 64 | /** 65 | * @see IoFilterChain#get(String) 66 | * 67 | * @param name The Filter's name we are looking for 68 | * @return The found Filter, or null 69 | */ 70 | EIoFilter* get(const char* name); 71 | 72 | /** 73 | * @see IoFilterChain#contains(String) 74 | * 75 | * @param name The Filter's name we want to check if it's in the chain 76 | * @return true if the chain contains the given filter name 77 | */ 78 | boolean contains(const char* name); 79 | 80 | /** 81 | * @see IoFilterChain#contains(IoFilter) 82 | * 83 | * @param filter The Filter we want to check if it's in the chain 84 | * @return true if the chain contains the given filter 85 | */ 86 | boolean contains(EIoFilter* filter); 87 | 88 | /** 89 | * @see IoFilterChain#addFirst(String, IoFilter) 90 | * 91 | * @param name The filter's name 92 | * @param filter The filter to add 93 | */ 94 | void addFirst(const char* name, EIoFilter* filter); 95 | 96 | /** 97 | * @see IoFilterChain#addLast(String, IoFilter) 98 | * 99 | * @param name The filter's name 100 | * @param filter The filter to add 101 | */ 102 | void addLast(const char* name, EIoFilter* filter); 103 | 104 | /** 105 | * @see IoFilterChain#addBefore(String, String, IoFilter) 106 | * 107 | * @param baseName The filter baseName 108 | * @param name The filter's name 109 | * @param filter The filter to add 110 | */ 111 | void addBefore(const char* baseName, const char* name, EIoFilter* filter); 112 | 113 | /** 114 | * @see IoFilterChain#addAfter(String, String, IoFilter) 115 | * 116 | * @param baseName The filter baseName 117 | * @param name The filter's name 118 | * @param filter The filter to add 119 | */ 120 | void addAfter(const char* baseName, const char* name, EIoFilter* filter); 121 | 122 | /** 123 | * @see IoFilterChain#remove(String) 124 | * 125 | * @param name The Filter's name to remove from the list of Filters 126 | * @return The removed IoFilter 127 | */ 128 | EIoFilter* remove(const char* name); 129 | 130 | /** 131 | * @see IoFilterChain#remove(IoFilter) 132 | * 133 | * @param filter The Filter we want to remove from the list of Filters 134 | * @return The removed IoFilter 135 | */ 136 | EIoFilter* remove(EIoFilter* filter); 137 | 138 | /** 139 | * @see IoFilterChain#clear() 140 | */ 141 | void clear(); 142 | 143 | /** 144 | * @see IoFilterChain#buildFilterChain(IoFilterChain) 145 | */ 146 | void buildFilterChain(EIoFilterChain* chain) THROWS(EException); 147 | 148 | /** 149 | * 150 | */ 151 | virtual EString toString(); 152 | 153 | private: 154 | ECopyOnWriteArrayList entries; 155 | 156 | void register_(int index, EIoFilterChain::Entry* e); 157 | void checkBaseName(const char* baseName); 158 | }; 159 | 160 | } /* namespace naf */ 161 | } /* namespace efc */ 162 | #endif /* NFILTERCHAINBUILDER_HH_ */ 163 | -------------------------------------------------------------------------------- /src/EHttpAcceptor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpAcceptor.cpp 3 | * 4 | * Created on: 2018-6-21 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EHttpAcceptor.hh" 9 | #include "../inc/EHttpSession.hh" 10 | 11 | namespace efc { 12 | namespace naf { 13 | 14 | EHttpAcceptor::~EHttpAcceptor() { 15 | 16 | } 17 | 18 | EHttpAcceptor::EHttpAcceptor(boolean rwIoDetached, boolean workerDetached) : 19 | rwIoDetached_(rwIoDetached), workerDetached_(workerDetached), handler_(null), requestChannel(100) { 20 | if (workerDetached) { 21 | rwIoDetached_ = true; //! unsupport (false, true) mode. 22 | } 23 | } 24 | 25 | void EHttpAcceptor::listen() { 26 | if (!workerDetached_) { 27 | for (int i=0; igetFiberScheduler().schedule([this](){ 29 | while (true) { 30 | try { 31 | processRequest(this->requestChannel.read()); 32 | } catch (...) { 33 | //... 34 | } 35 | } 36 | }); 37 | } 38 | } else { 39 | for (int i=0; i worker = new EEThreadTarget([this](){ 41 | while (true) { 42 | try { 43 | processRequest(this->requestChannel.read()); 44 | } catch (...) { 45 | //... 46 | } 47 | } 48 | }); 49 | EThread::setDaemon(worker, true); 50 | worker->start(); 51 | } 52 | } 53 | 54 | ESocketAcceptor::listen(); //!!! 55 | } 56 | 57 | sp EHttpAcceptor::newSession(EIoService *service, sp& socket) { 58 | return dynamic_cast(new EHttpSession(service, socket)); 59 | } 60 | 61 | void EHttpAcceptor::onConnectionHandle(sp& session, ESocketAcceptor::Service* service) { 62 | // supper call 63 | ESocketAcceptor::onConnectionHandle(session, service); 64 | 65 | sp hs = dynamic_pointer_cast(session); 66 | 67 | // let write message in another fiber. 68 | if (rwIoDetached_) { 69 | detachWriteRoutine(hs); 70 | } 71 | 72 | if (handler_) { 73 | // on opened. 74 | handler_->sessionOpened(hs); 75 | } 76 | 77 | // let read message in current fiber. 78 | sp request; 79 | while ((request = dynamic_pointer_cast(session->read())) != null) { 80 | // 81 | } 82 | 83 | if (handler_) { 84 | // on closed. 85 | handler_->sessionClosed(hs); 86 | } 87 | } 88 | 89 | void EHttpAcceptor::setHttpHandler(EHttpHandler* handler) { 90 | handler_ = handler; 91 | } 92 | 93 | boolean EHttpAcceptor::isRWIoDetached() { 94 | return rwIoDetached_; 95 | } 96 | 97 | boolean EHttpAcceptor::isWorkerDetached() { 98 | return workerDetached_; 99 | } 100 | 101 | void EHttpAcceptor::processRequest(sp request) { 102 | HeaderMapPtr headers = request->getHeaderMap(); 103 | HeaderEntry* he = headers->Method(); 104 | EString method = he->value().c_str(); 105 | 106 | ActiveStream* stream = request->getHttpStream(); 107 | sp session = stream->getHttpSession(); 108 | sp response(new EHttpResponse(stream)); 109 | 110 | // service 111 | handler_->service(session, request, response); 112 | 113 | if (method.equalsIgnoreCase("GET")) { 114 | handler_->doGet(session, request, response); 115 | } else if (method.equalsIgnoreCase("HEAD")) { 116 | handler_->doHead(session, request, response); 117 | } else if (method.equalsIgnoreCase("POST")) { 118 | handler_->doPost(session, request, response); 119 | } else if (method.equalsIgnoreCase("PUT")) { 120 | handler_->doPut(session, request, response); 121 | } else if (method.equalsIgnoreCase("DELETE")) { 122 | handler_->doDelete(session, request, response); 123 | } else if (method.equalsIgnoreCase("OPTIONS")) { 124 | handler_->doOptions(session, request, response); 125 | } else if (method.equalsIgnoreCase("TRACE")) { 126 | handler_->doTrace(session, request, response); 127 | } else if (method.equalsIgnoreCase("PATCH")) { 128 | handler_->doPatch(session, request, response); 129 | } 130 | 131 | // response. 132 | if (isRWIoDetached()) { 133 | session->responseChannel.write(response); 134 | } else { 135 | stream->encodeHeaders(response->getHeaderMap(), (response->bodyData == null)); 136 | 137 | if (response->bodyData != null) { 138 | Http::Buffer::OwnedImpl buffer; 139 | buffer.add(response->bodyData); 140 | stream->encodeData(buffer, false); 141 | buffer.clear(); 142 | stream->encodeData(buffer, true); 143 | } 144 | } 145 | } 146 | 147 | void EHttpAcceptor::detachWriteRoutine(sp& session) { 148 | this->getFiberScheduler().scheduleInheritThread([session](){ 149 | while (!session->isClosed()) { 150 | try { 151 | auto response = session->responseChannel.read(); 152 | if (dynamic_pointer_cast(response) != null) { 153 | break; 154 | } 155 | 156 | ActiveStream* stream = response->stream; 157 | 158 | stream->encodeHeaders(response->headerMap, (response->bodyData == null)); 159 | 160 | if (response->bodyData != null) { 161 | Http::Buffer::OwnedImpl buffer; 162 | buffer.add(response->bodyData); 163 | stream->encodeData(buffer, false); 164 | buffer.clear(); 165 | stream->encodeData(buffer, true); 166 | } 167 | } catch (EInterruptedException& e) { 168 | break; 169 | } 170 | } 171 | }); 172 | } 173 | 174 | } /* namespace naf */ 175 | } /* namespace efc */ 176 | -------------------------------------------------------------------------------- /http/source/header_map_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../include/header_map.h" 10 | 11 | #include "./headers.h" 12 | 13 | namespace efc { 14 | namespace naf { 15 | namespace Http { 16 | 17 | /** 18 | * These are definitions of all of the inline header access functions described inside header_map.h 19 | */ 20 | #define DEFINE_INLINE_HEADER_FUNCS(name) \ 21 | public: \ 22 | const HeaderEntry* name() const override { return inline_headers_.name##_; } \ 23 | HeaderEntry* name() override { return inline_headers_.name##_; } \ 24 | HeaderEntry& insert##name() override { \ 25 | return maybeCreateInline(&inline_headers_.name##_, Headers::get().name); \ 26 | } \ 27 | void remove##name() override { removeInline(&inline_headers_.name##_); } 28 | 29 | #define DEFINE_INLINE_HEADER_STRUCT(name) HeaderEntryImpl* name##_; 30 | 31 | /** 32 | * Implementation of Http::HeaderMap. This is heavily optimized for performance. Roughly, when 33 | * headers are added to the map, we do a hash lookup to see if it's one of the O(1) headers. 34 | * If it is, we store a reference to it that can be accessed later directly. Most high performance 35 | * paths use O(1) direct access. In general, we try to copy as little as possible and allocate as 36 | * little as possible in any of the paths. 37 | */ 38 | class HeaderMapImpl: public HeaderMap { 39 | public: 40 | HeaderMapImpl(); 41 | HeaderMapImpl( 42 | const std::initializer_list>& values); 43 | HeaderMapImpl(const HeaderMap& rhs); 44 | 45 | /** 46 | * Add a header via full move. This is the expected high performance paths for codecs populating 47 | * a map when receiving. 48 | */ 49 | void addViaMove(HeaderString&& key, HeaderString&& value); 50 | 51 | /** 52 | * For testing. Equality is based on equality of the backing list. This is an exact match 53 | * comparison (order matters). 54 | */ 55 | bool operator==(const HeaderMapImpl& rhs) const; 56 | 57 | // Http::HeaderMap 58 | void addReference(const LowerCaseString& key, const std::string& value) override; 59 | void addReferenceKey(const LowerCaseString& key, uint64_t value) override; 60 | void addReferenceKey(const LowerCaseString& key, const std::string& value) override; 61 | void addCopy(const LowerCaseString& key, uint64_t value) override; 62 | void addCopy(const LowerCaseString& key, const std::string& value) override; 63 | void setReference(const LowerCaseString& key, const std::string& value) override; 64 | void setReferenceKey(const LowerCaseString& key, const std::string& value) override; 65 | uint64_t byteSize() const override; 66 | const HeaderEntry* get(const LowerCaseString& key) const override; 67 | HeaderEntry* get(const LowerCaseString& key) override; 68 | void iterate(ConstIterateCb cb, void* context) const override; 69 | void iterateReverse(ConstIterateCb cb, void* context) const override; 70 | Lookup lookup(const LowerCaseString& key, const HeaderEntry** entry) const override; 71 | void remove(const LowerCaseString& key) override; 72 | size_t size() const override {return headers_.size();} 73 | 74 | protected: 75 | struct HeaderEntryImpl : public HeaderEntry, NonCopyable { 76 | HeaderEntryImpl(const LowerCaseString& key); 77 | HeaderEntryImpl(const LowerCaseString& key, HeaderString&& value); 78 | HeaderEntryImpl(HeaderString&& key, HeaderString&& value); 79 | 80 | // HeaderEntry 81 | const HeaderString& key() const override {return key_;} 82 | void value(const char* value, uint32_t size) override; 83 | void value(const std::string& value) override; 84 | void value(uint64_t value) override; 85 | void value(const HeaderEntry& header) override; 86 | const HeaderString& value() const override {return value_;} 87 | HeaderString& value() override {return value_;} 88 | 89 | HeaderString key_; 90 | HeaderString value_; 91 | std::list::iterator entry_; 92 | }; 93 | 94 | struct StaticLookupResponse { 95 | HeaderEntryImpl** entry_; 96 | const LowerCaseString* key_; 97 | }; 98 | 99 | struct StaticLookupEntry { 100 | typedef StaticLookupResponse (*EntryCb)(HeaderMapImpl&); 101 | 102 | EntryCb cb_ {}; 103 | std::array, 256> entries_; 104 | }; 105 | 106 | /** 107 | * This is the static lookup table that is used to determine whether a header is one of the O(1) 108 | * headers. This uses a trie for lookup time at most equal to the size of the incoming string. 109 | */ 110 | struct StaticLookupTable { 111 | StaticLookupTable(); 112 | void add(const char* key, StaticLookupEntry::EntryCb cb); 113 | StaticLookupEntry::EntryCb find(const char* key) const; 114 | 115 | StaticLookupEntry root_; 116 | }; 117 | 118 | struct AllInlineHeaders { 119 | ALL_INLINE_HEADERS(DEFINE_INLINE_HEADER_STRUCT) 120 | }; 121 | 122 | void insertByKey(HeaderString&& key, HeaderString&& value); 123 | HeaderEntryImpl& maybeCreateInline(HeaderEntryImpl** entry, const LowerCaseString& key); 124 | HeaderEntryImpl& maybeCreateInline(HeaderEntryImpl** entry, const LowerCaseString& key, 125 | HeaderString&& value); 126 | void removeInline(HeaderEntryImpl** entry); 127 | 128 | AllInlineHeaders inline_headers_; 129 | std::list headers_; 130 | 131 | ALL_INLINE_HEADERS(DEFINE_INLINE_HEADER_FUNCS) 132 | }; 133 | 134 | typedef sp HeaderMapImplPtr; 135 | 136 | } // namespace http 137 | } // namespace naf 138 | } // namespace efc 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CxxConet 2 | 3 | ## 基于协程的C++网络开发框架. 4 | 5 | ### 目录 6 | - [特点](#特点) 7 | - [协程模型](#协程模型) 8 | - [通信流程](#通信流程) 9 | - [示例](#示例) 10 | - [性能](#性能) 11 | - [依赖](#依赖) 12 | - [Support](#support) 13 | 14 | #### 特点 15 | * 跨平台:同时支持Linux32/64、OSX64两个平台,支持C++11及以上; 16 | * 易开发:同步的方式编写代码,支持类Mina的filter过滤链、简单而不失强大; 17 | * 高性能:可同时处理海量连接,框架无锁设计,性能超群; 18 | * 多特性:代码同步调用方式、支持网络过载保护、支持空闲连接自动清理等企业级特性; 19 | 20 | #### 协程模型 21 | 在整个CxxConet框架中,共有4种工作协程: 22 | * Socket接入协程(socket acceptor) 23 | * 全局指标统计协程(global statistics) 24 | * Socket清理协程(clean handler) 25 | * I/O处理协程(connection handler) 26 | 27 | ![fiber](img/fiber.png) 28 | 29 | > Socket接入协程:负责accept新的client连接,然后创建`I/O处理协程`并将client连接交由该协程去处理上层事务; 30 | 31 | > 全局指标统计协程:定期汇总各协程的统计指标,无锁实现全局汇总数据; 32 | 33 | > Socket清理协程:定期清理Idle连接,防止资源耗尽; 34 | 35 | > I/O处理协程:每个Client连接独立一个处理协程,包括读写及上层事务处理; 36 | 37 | > Socket接入协程、全局指标统计协程、Socket清理协程共享同一个线程,I/O处理协程则位于其他独立线程。 38 | 39 | #### 通信流程 40 | ![ioflow](img/ioflow.png) 41 | 42 | > IoAcceptor:这个接口在一个协程上负责套接字的建立; 43 | 44 | > IoFilter: 这个接口定义一组拦截器,这些拦截器可以包括日志输出、黑名单过滤、数据的编码(write 方向)与解码(read 方向)等功能; 45 | 46 | > ConnectionHandler:这个接口负责编写业务逻辑,也就是接收、发送数据的地方。 47 | 48 | #### 示例 49 | `c++:` 50 | 51 | ``` 52 | #include "ENaf.hh" 53 | 54 | static sp logger = ELoggerManager::getLogger("testnaf"); 55 | 56 | static void onListening(ESocketAcceptor* acceptor) { 57 | logger->trace("onListening..."); 58 | 59 | while (!acceptor->isDisposed()) { 60 | sleep(10); 61 | 62 | EIoServiceStatistics* ss = acceptor->getStatistics(); 63 | logger->trace_("ReadBytes=%ld", ss->getReadBytes()); 64 | logger->trace_("WrittenBytes=%ld", ss->getWrittenBytes()); 65 | } 66 | 67 | logger->trace("Out of Listening."); 68 | } 69 | 70 | static void onConnection(ESocketSession* session) { 71 | logger->trace("onConnection..."); 72 | 73 | sp request; 74 | while(!session->getService()->isDisposed()) { 75 | try { 76 | request = dynamic_pointer_cast(session->read()); 77 | } catch (ESocketTimeoutException& e) { 78 | logger->trace("session read timeout."); 79 | continue; 80 | } catch (EIOException& e) { 81 | logger->trace("session read error."); 82 | break; 83 | } 84 | if (request == null) { 85 | logger->trace("session client closed."); 86 | break; 87 | } 88 | 89 | // echo. 90 | session->write(request); 91 | } 92 | 93 | logger->trace("Out of Connection."); 94 | } 95 | 96 | int main(int argc, const char **argv) { 97 | // CxxJDK init. 98 | ESystem::init(argc, argv); 99 | // CxxLog4j init. 100 | ELoggerManager::init("log4e.conf"); 101 | 102 | ESocketAcceptor sa; 103 | EBlacklistFilter blf; 104 | blf.block("localhost"); 105 | sa.getFilterChainBuilder()->addFirst("black", &blf); 106 | sa.setListeningHandler(onListening); 107 | sa.setConnectionHandler(onConnection); 108 | sa.setMaxConnections(1000000); 109 | sa.setSoTimeout(3000); 110 | sa.setSessionIdleTime(EIdleStatus::WRITER_IDLE, 30); 111 | sa.bind("0.0.0.0", 8888); 112 | sa.listen(); 113 | 114 | ESystem::exit(0); 115 | 116 | return 0; 117 | } 118 | 119 | ``` 120 | 121 | 更多示例: 122 | [testnaf.cpp](test/testnaf.cpp) 123 | 124 | #### 性能 125 | 126 | `测试程序:` 127 | 128 | 见示例c++代码:[benchmark.cpp](test/benchmark.cpp); 129 | 130 | `软件环境:` 131 | 132 | ``` 133 | # cat /etc/redhat-release 134 | CentOS release 6.4 (Final) 135 | # uname -a 136 | Linux cxxjava 2.6.32-358.el6.x86_64 #1 SMP Fri Feb 22 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux 137 | ``` 138 | 139 | 140 | `硬件环境:` 141 | 142 | ``` 143 | 型号名称: R6240-12 144 | 处理器名称: Intel Xeon E5606 145 | 处理器速度: 2.13GHz 146 | 处理器数目: 4 147 | 核总数: 8 148 | ``` 149 | `测试结果:` 150 | 151 | ``` 152 | # ab -c 20 -n 50000 http://localhost:8888/ 153 | This is ApacheBench, Version 2.3 <$Revision: 655654 $> 154 | Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ 155 | Licensed to The Apache Software Foundation, http://www.apache.org/ 156 | 157 | Benchmarking localhost (be patient) 158 | Completed 5000 requests 159 | Completed 10000 requests 160 | Completed 15000 requests 161 | Completed 20000 requests 162 | Completed 25000 requests 163 | Completed 30000 requests 164 | Completed 35000 requests 165 | Completed 40000 requests 166 | Completed 45000 requests 167 | Completed 50000 requests 168 | Finished 50000 requests 169 | 170 | 171 | Server Software: 172 | Server Hostname: localhost 173 | Server Port: 8888 174 | 175 | Document Path: / 176 | Document Length: 3 bytes 177 | 178 | Concurrency Level: 20 179 | Time taken for tests: 4.077 seconds 180 | Complete requests: 50000 181 | Failed requests: 0 182 | Write errors: 0 183 | Total transferred: 2050328 bytes 184 | HTML transferred: 150024 bytes 185 | Requests per second: 12264.64 [#/sec] (mean) 186 | Time per request: 1.631 [ms] (mean) 187 | Time per request: 0.082 [ms] (mean, across all concurrent requests) 188 | Transfer rate: 491.14 [Kbytes/sec] received 189 | 190 | Connection Times (ms) 191 | min mean[+/-sd] median max 192 | Connect: 0 1 0.1 1 4 193 | Processing: 0 1 0.3 1 16 194 | Waiting: 0 1 0.3 1 16 195 | Total: 0 2 0.3 2 17 196 | 197 | Percentage of the requests served within a certain time (ms) 198 | 50% 2 199 | 66% 2 200 | 75% 2 201 | 80% 2 202 | 90% 2 203 | 95% 2 204 | 98% 2 205 | 99% 2 206 | 100% 17 (longest request) 207 | ``` 208 | 209 | #### 依赖 210 | 1. [CxxJDK](https://github.com/cxxjava/CxxJDK) 211 | 2. [CxxFiber](https://github.com/cxxjava/CxxFiber) 212 | 3. [CxxLog4j](https://github.com/cxxjava/CxxLog4j) 213 | 214 | 215 | #### Support 216 | Email: [cxxjava@163.com](mailto:cxxjava@163.com) -------------------------------------------------------------------------------- /test/httpserver.cpp: -------------------------------------------------------------------------------- 1 | #include "es_main.h" 2 | #include "ENaf.hh" 3 | #include "../inc/EHttpAcceptor.hh" 4 | 5 | #define LOG(fmt,...) ESystem::out->printfln(fmt, ##__VA_ARGS__) 6 | 7 | #define PRINT_STATISTICS 0 8 | 9 | static EHttpAcceptor* g_sa = NULL; 10 | static boolean g_shutdown = false; 11 | 12 | static void onListening(ESocketAcceptor* acceptor) { 13 | LOG("onListening..."); 14 | 15 | #if PRINT_STATISTICS 16 | while (!acceptor->isDisposed()) { 17 | sleep(10); 18 | 19 | EIoServiceStatistics* ss = acceptor->getStatistics(); 20 | LOG("CumulativeManagedSessionCount=%ld", ss->getCumulativeManagedSessionCount()); 21 | LOG("LargestManagedSessionCount=%ld", ss->getLargestManagedSessionCount()); 22 | LOG("LargestReadBytesThroughput=%lf", ss->getLargestReadBytesThroughput()); 23 | LOG("LargestReadMessagesThroughput=%lf", ss->getLargestReadMessagesThroughput()); 24 | LOG("LargestWrittenBytesThroughput=%lf", ss->getLargestWrittenBytesThroughput()); 25 | LOG("getLargestWrittenMessagesThroughput=%lf", ss->getLargestWrittenMessagesThroughput()); 26 | LOG("LastIoTime=%ld", ss->getLastIoTime()); 27 | LOG("LastReadTime=%ld", ss->getLastReadTime()); 28 | LOG("LastWriteTime=%ld", ss->getLastWriteTime()); 29 | LOG("ReadBytes=%ld", ss->getReadBytes()); 30 | LOG("ReadBytesThroughput=%lf", ss->getReadBytesThroughput()); 31 | LOG("ReadMessages=%ld", ss->getReadMessages()); 32 | LOG("ReadMessagesThroughput=%lf", ss->getReadMessagesThroughput()); 33 | LOG("WrittenBytes=%ld", ss->getWrittenBytes()); 34 | LOG("WrittenBytesThroughput=%lf", ss->getWrittenBytesThroughput()); 35 | LOG("WrittenMessages=%ld", ss->getWrittenMessages()); 36 | LOG("WrittenMessagesThroughput=%lf", ss->getWrittenMessagesThroughput()); 37 | LOG("\n"); 38 | } 39 | #endif 40 | } 41 | 42 | static void onConnection(sp& session, ESocketAcceptor::Service* service) { 43 | LOG("onConnection: service=%s", service->toString().c_str()); 44 | } 45 | 46 | class HttpHandler : public EHttpHandler { 47 | public: 48 | virtual void service(sp& session, sp& request, sp& response) { 49 | LOG("service()..."); 50 | } 51 | 52 | virtual void doGet(sp& session, sp& request, sp& response) { 53 | LOG("doGet()..."); 54 | 55 | HeaderMapPtr headers = request->getHeaderMap(); 56 | headers->iterate( 57 | [](const HeaderEntry& header, void* context) -> HeaderMap::Iterate { 58 | printf(" '%s':'%s'", 59 | header.key().c_str(), header.value().c_str()); 60 | return HeaderMap::Iterate::Continue; 61 | }, 62 | NULL); 63 | printf("\n"); 64 | 65 | ELinkedList > body = request->getBodyData(); 66 | for (auto buffer : body) { 67 | printf("%s\n", buffer->current()); 68 | } 69 | 70 | // response. 71 | response->getHeaderMap().addReferenceKey(Headers::get().ContentLength, 5); 72 | response->write("kkk", 3); 73 | response->write("aaa", 3); 74 | } 75 | 76 | virtual void doPost(sp& session, sp& request, sp& response) { 77 | LOG("doPost()..."); 78 | 79 | HeaderMapPtr headers = request->getHeaderMap(); 80 | headers->iterate( 81 | [](const HeaderEntry& header, void* context) -> HeaderMap::Iterate { 82 | printf(" '%s':'%s'", 83 | header.key().c_str(), header.value().c_str()); 84 | return HeaderMap::Iterate::Continue; 85 | }, 86 | NULL); 87 | printf("\n"); 88 | 89 | ELinkedList > body = request->getBodyData(); 90 | for (auto buffer : body) { 91 | printf("%s\n", buffer->current()); 92 | } 93 | 94 | // response. 95 | response->write("kkk", 3); 96 | } 97 | }; 98 | 99 | static void test_echo_server() { 100 | EHttpAcceptor sa(false, true); 101 | g_sa = &sa; 102 | 103 | EBlacklistFilter blf; 104 | EWhitelistFilter wlf; 105 | HttpHandler handler; 106 | blf.block("localhost"); 107 | //sa.getFilterChainBuilder()->addFirst("black", &blf); 108 | wlf.allow("localhost"); 109 | //sa.getFilterChainBuilder()->addFirst("white", &wlf); 110 | // EHttpCodecFilter hcf; 111 | //sa.getFilterChainBuilder()->addLast("http", &hcf); 112 | sa.setListeningHandler(onListening); 113 | sa.setConnectionHandler(onConnection); 114 | //sa.setMaxConnections(10); 115 | //sa.setSoTimeout(30000); 116 | //sa.setSessionIdleTime(EIdleStatus::WRITER_IDLE, 30); 117 | sa.setReuseAddress(true); 118 | sa.setHttpHandler(&handler); 119 | sa.bind("0.0.0.0", 8887, false, "serviceA", [](ESocketAcceptor::Service& service){ 120 | LOG("service [%s] is active.", service.toString().c_str()); 121 | }); 122 | sa.bind("localhost", 8889, true, "serviceB", [](ESocketAcceptor::Service& service){ 123 | LOG("service [%s] is active.", service.toString().c_str()); 124 | 125 | if (service.sslActive) { 126 | sp sss = dynamic_pointer_cast(service.ss); 127 | sss->setSSLParameters( 128 | "./certs/tests-cert.pem", 129 | "./certs/tests-key.pem", 130 | null); 131 | sss->setNegotiatedProtocols("h2", "http/1.1", NULL); 132 | } 133 | }); 134 | sa.listen(); 135 | } 136 | 137 | static void test_test(int argc, const char** argv) { 138 | test_echo_server(); 139 | } 140 | 141 | static void sigfunc(int sig_no) { 142 | if (!g_shutdown) { 143 | g_shutdown = true; 144 | } else { 145 | ESystem::exit(-1); 146 | } 147 | 148 | /** 149 | * signal handler is running in main thread!!! 150 | */ 151 | LOG("signaled."); 152 | g_sa->shutdown(); 153 | } 154 | 155 | MAIN_IMPL(testnaf_http) { 156 | printf("main()\n"); 157 | 158 | ESystem::init(argc, argv); 159 | ELoggerManager::init("log4e.conf"); 160 | 161 | signal(SIGINT, sigfunc); 162 | 163 | printf("inited.\n"); 164 | 165 | int i = 0; 166 | try { 167 | boolean loop = EBoolean::parseBoolean(ESystem::getProgramArgument("loop")); 168 | do { 169 | test_test(argc, argv); 170 | 171 | // } while (++i < 5); 172 | } while (0); 173 | } 174 | catch (EException& e) { 175 | e.printStackTrace(); 176 | } 177 | catch (...) { 178 | printf("catch all...\n"); 179 | } 180 | 181 | printf("exit...\n"); 182 | 183 | ESystem::exit(0); 184 | 185 | return 0; 186 | } 187 | -------------------------------------------------------------------------------- /http/source/headers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../include/header_map.h" 6 | #include "./const_singleton.h" 7 | 8 | namespace efc { 9 | namespace naf { 10 | namespace Http { 11 | 12 | /** 13 | * Constant HTTP headers and values. All lower case. 14 | */ 15 | class HeaderValues { 16 | public: 17 | const LowerCaseString Accept{"accept"}; 18 | const LowerCaseString AcceptEncoding{"accept-encoding"}; 19 | const LowerCaseString AccessControlRequestHeaders{"access-control-request-headers"}; 20 | const LowerCaseString AccessControlRequestMethod{"access-control-request-method"}; 21 | const LowerCaseString AccessControlAllowOrigin{"access-control-allow-origin"}; 22 | const LowerCaseString AccessControlAllowHeaders{"access-control-allow-headers"}; 23 | const LowerCaseString AccessControlAllowMethods{"access-control-allow-methods"}; 24 | const LowerCaseString AccessControlExposeHeaders{"access-control-expose-headers"}; 25 | const LowerCaseString AccessControlMaxAge{"access-control-max-age"}; 26 | const LowerCaseString AccessControlAllowCredentials{"access-control-allow-credentials"}; 27 | const LowerCaseString Authorization{"authorization"}; 28 | const LowerCaseString CacheControl{"cache-control"}; 29 | const LowerCaseString ClientTraceId{"x-client-trace-id"}; 30 | const LowerCaseString Connection{"connection"}; 31 | const LowerCaseString ContentEncoding{"content-encoding"}; 32 | const LowerCaseString ContentLength{"content-length"}; 33 | const LowerCaseString ContentType{"content-type"}; 34 | const LowerCaseString Cookie{"cookie"}; 35 | const LowerCaseString Date{"date"}; 36 | const LowerCaseString Etag{"etag"}; 37 | const LowerCaseString Expect{"expect"}; 38 | const LowerCaseString ForwardedClientCert{"x-forwarded-client-cert"}; 39 | const LowerCaseString ForwardedFor{"x-forwarded-for"}; 40 | const LowerCaseString ForwardedProto{"x-forwarded-proto"}; 41 | const LowerCaseString GrpcMessage{"grpc-message"}; 42 | const LowerCaseString GrpcStatus{"grpc-status"}; 43 | const LowerCaseString GrpcAcceptEncoding{"grpc-accept-encoding"}; 44 | const LowerCaseString Host{":authority"}; 45 | const LowerCaseString HostLegacy{"host"}; 46 | const LowerCaseString KeepAlive{"keep-alive"}; 47 | const LowerCaseString LastModified{"last-modified"}; 48 | const LowerCaseString Location{"location"}; 49 | const LowerCaseString Method{":method"}; 50 | const LowerCaseString Origin{"origin"}; 51 | const LowerCaseString OtSpanContext{"x-ot-span-context"}; 52 | const LowerCaseString Path{":path"}; 53 | const LowerCaseString ProxyConnection{"proxy-connection"}; 54 | const LowerCaseString Referer{"referer"}; 55 | const LowerCaseString RequestId{"x-request-id"}; 56 | const LowerCaseString Scheme{":scheme"}; 57 | const LowerCaseString Server{"server"}; 58 | const LowerCaseString SetCookie{"set-cookie"}; 59 | const LowerCaseString Status{":status"}; 60 | const LowerCaseString TransferEncoding{"transfer-encoding"}; 61 | const LowerCaseString TE{"te"}; 62 | const LowerCaseString Upgrade{"upgrade"}; 63 | const LowerCaseString UserAgent{"user-agent"}; 64 | const LowerCaseString Vary{"vary"}; 65 | const LowerCaseString XB3TraceId{"x-b3-traceid"}; 66 | const LowerCaseString XB3SpanId{"x-b3-spanid"}; 67 | const LowerCaseString XB3ParentSpanId{"x-b3-parentspanid"}; 68 | const LowerCaseString XB3Sampled{"x-b3-sampled"}; 69 | const LowerCaseString XB3Flags{"x-b3-flags"}; 70 | const LowerCaseString XContentTypeOptions{"x-content-type-options"}; 71 | const LowerCaseString XSquashDebug{"x-squash-debug"}; 72 | 73 | struct { 74 | const std::string Close{"close"}; 75 | const std::string KeepAlive{"keep-alive"}; 76 | const std::string Upgrade{"upgrade"}; 77 | } ConnectionValues; 78 | 79 | struct { 80 | const std::string WebSocket{"websocket"}; 81 | } UpgradeValues; 82 | 83 | struct { 84 | const std::string NoCacheMaxAge0{"no-cache, max-age=0"}; 85 | const std::string NoTransform{"no-transform"}; 86 | } CacheControlValues; 87 | 88 | struct { 89 | const std::string Text{"text/plain"}; 90 | const std::string TextUtf8{"text/plain; charset=UTF-8"}; // TODO(jmarantz): fold this into Text 91 | const std::string Html{"text/html; charset=UTF-8"}; 92 | const std::string Grpc{"application/grpc"}; 93 | const std::string GrpcWeb{"application/grpc-web"}; 94 | const std::string GrpcWebProto{"application/grpc-web+proto"}; 95 | const std::string GrpcWebText{"application/grpc-web-text"}; 96 | const std::string GrpcWebTextProto{"application/grpc-web-text+proto"}; 97 | const std::string Json{"application/json"}; 98 | } ContentTypeValues; 99 | 100 | struct { 101 | const std::string _100Continue{"100-continue"}; 102 | } ExpectValues; 103 | 104 | struct { 105 | const std::string Get{"GET"}; 106 | const std::string Head{"HEAD"}; 107 | const std::string Post{"POST"}; 108 | const std::string Options{"OPTIONS"}; 109 | } MethodValues; 110 | 111 | struct { 112 | const std::string Http{"http"}; 113 | const std::string Https{"https"}; 114 | } SchemeValues; 115 | 116 | struct { 117 | const std::string Chunked{"chunked"}; 118 | const std::string Deflate{"deflate"}; 119 | const std::string Gzip{"gzip"}; 120 | } TransferEncodingValues; 121 | 122 | struct { 123 | const std::string Default{"identity,deflate,gzip"}; 124 | } GrpcAcceptEncodingValues; 125 | 126 | struct { 127 | const std::string Trailers{"trailers"}; 128 | } TEValues; 129 | 130 | struct { 131 | const std::string Nosniff{"nosniff"}; 132 | } XContentTypeOptionValues; 133 | 134 | struct { 135 | const std::string True{"true"}; 136 | } CORSValues; 137 | 138 | struct { 139 | const std::string Http10String{"HTTP/1.0"}; 140 | const std::string Http11String{"HTTP/1.1"}; 141 | const std::string Http2String{"HTTP/2"}; 142 | } ProtocolStrings; 143 | 144 | struct { 145 | const std::string Gzip{"gzip"}; 146 | const std::string Identity{"identity"}; 147 | const std::string Wildcard{"*"}; 148 | } AcceptEncodingValues; 149 | 150 | struct { 151 | const std::string Gzip{"gzip"}; 152 | } ContentEncodingValues; 153 | 154 | struct { 155 | const std::string AcceptEncoding{"Accept-Encoding"}; 156 | const std::string Wildcard{"*"}; 157 | } VaryValues; 158 | }; 159 | 160 | typedef ConstSingleton Headers; 161 | 162 | } // namespace Http 163 | } // namespace naf 164 | } // namespace efc 165 | -------------------------------------------------------------------------------- /inc/EIoSession.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoSession.hh 3 | * 4 | * Created on: 2013-8-19 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EIOSESSION_HH_ 9 | #define EIOSESSION_HH_ 10 | 11 | #include "Efc.hh" 12 | 13 | namespace efc { 14 | namespace naf { 15 | 16 | class EIoService; 17 | class EIoFilterChain; 18 | 19 | /** 20 | * A handle which represents connection between two end-points regardless of 21 | * transport types. 22 | *

23 | * {@link IoSession} provides user-defined attributes. User-defined attributes 24 | * are application-specific data which are associated with a session. 25 | * It often contains objects that represents the state of a higher-level protocol 26 | * and becomes a way to exchange data between filters and handlers. 27 | *

28 | *

Adjusting Transport Type Specific Properties

29 | *

30 | * You can simply downcast the session to an appropriate subclass. 31 | *

32 | *

33 | */ 34 | abstract class EIoSession: virtual public EObject { 35 | public: 36 | virtual ~EIoSession(); 37 | 38 | /** 39 | * @return a unique identifier for this session. Every session has its own 40 | * ID which is different from each other. 41 | */ 42 | virtual long getId(); 43 | 44 | /** 45 | * @return the {@link IoService} which provides I/O service to this session. 46 | */ 47 | virtual EIoService* getService(); 48 | 49 | /** 50 | * @return the filter chain that only affects this session. 51 | */ 52 | virtual EIoFilterChain* getFilterChain(); 53 | 54 | /** 55 | * @return a {@link ReadFuture} which is notified when a new message is 56 | * received, the connection is closed or an exception is caught. This 57 | * operation is especially useful when you implement a client application. 58 | * TODO : Describe here how we enable this feature. 59 | * However, please note that this operation is disabled by default and 60 | * throw {@link IllegalStateException} because all received events must be 61 | * queued somewhere to support this operation, possibly leading to memory 62 | * leak. This means you have to keep calling {@link #read()} once you 63 | * enabled this operation. To enable this operation, please call 64 | * {@link IoSessionConfig#setUseReadOperation(boolean)} with true. 65 | * 66 | * @throws IllegalStateException if 67 | * {@link IoSessionConfig#setUseReadOperation(boolean) useReadOperation} 68 | * option has not been enabled. 69 | */ 70 | virtual sp read() = 0; 71 | 72 | /** 73 | * Writes the specified message to remote peer. This 74 | * operation is asynchronous; {@link IoHandler#messageSend(IoSession,Object)} 75 | * will be invoked when the message is actually sent to remote peer. 76 | * You can also wait for the returned {@link WriteFuture} if you want 77 | * to wait for the message actually written. 78 | * 79 | * @param data The message data to write 80 | * @param size The message data size 81 | * @return The associated WriteFuture 82 | */ 83 | virtual boolean write(sp message) = 0; 84 | 85 | /** 86 | * Closes this session immediately or after all queued write requests 87 | * are flushed. This operation is asynchronous. Wait for the returned 88 | * {@link CloseFuture} if you want to wait for the session actually closed. 89 | * 90 | */ 91 | virtual void close() = 0; 92 | 93 | /** 94 | * @return true if the session has started and initialized a SslEngine, 95 | * false if the session is not yet secured (the handshake is not completed) 96 | * or if SSL is not set for this session, or if SSL is not even an option. 97 | */ 98 | virtual boolean isSecured() = 0; 99 | 100 | /** 101 | * Returns the socket address of remote peer. 102 | */ 103 | virtual EInetSocketAddress* getRemoteAddress() = 0; 104 | 105 | /** 106 | * Returns the socket address of local machine which is associated with this 107 | * session. 108 | */ 109 | virtual EInetSocketAddress* getLocalAddress() = 0; 110 | 111 | /** 112 | * @return the session's creation time in milliseconds 113 | */ 114 | virtual llong getCreationTime(); 115 | 116 | /** 117 | * Returns the time in millis when I/O occurred lastly. 118 | */ 119 | virtual llong getLastIoTime(); 120 | 121 | /** 122 | * Returns the time in millis when read operation occurred lastly. 123 | */ 124 | virtual llong getLastReadTime(); 125 | 126 | /** 127 | * Returns the time in millis when write operation occurred lastly. 128 | */ 129 | virtual llong getLastWriteTime(); 130 | 131 | public: 132 | EHashMap > attributes; 133 | 134 | /** 135 | * 136 | */ 137 | EObject* attach(EObject* ob); 138 | EObject* attachment(); 139 | 140 | protected: 141 | friend class EIoFilterChain; 142 | 143 | /** The session ID */ 144 | long sessionId; 145 | 146 | /* Statistics variables */ 147 | llong creationTime; 148 | llong lastReadTime; 149 | llong lastWriteTime; 150 | long readBytes; 151 | long writtenBytes; 152 | long readMessages; 153 | long writtenMessages; 154 | 155 | EIoService* service; 156 | 157 | EAtomicReference attachment_; 158 | 159 | /** The FilterChain created for this session */ 160 | EIoFilterChain* filterChain; 161 | 162 | /** An id generator guaranteed to generate unique IDs for the session */ 163 | static long idGenerator; 164 | 165 | /** 166 | * Create a Session for a service 167 | * 168 | * @param service the Service for this session 169 | */ 170 | EIoSession(EIoService* service); 171 | 172 | /** 173 | * Increase the number of read bytes 174 | * 175 | * @param increment The number of read bytes 176 | * @param currentTime The current time 177 | */ 178 | void increaseReadBytes(long increment, llong currentTime); 179 | 180 | /** 181 | * Increase the number of read messages 182 | * 183 | * @param currentTime The current time 184 | */ 185 | void increaseReadMessages(llong currentTime); 186 | 187 | /** 188 | * Increase the number of written bytes 189 | * 190 | * @param increment The number of written bytes 191 | * @param currentTime The current time 192 | */ 193 | void increaseWrittenBytes(int increment, llong currentTime); 194 | 195 | /** 196 | * Increase the number of written messages 197 | * 198 | * @param currentTime The current tile 199 | */ 200 | void increaseWrittenMessages(llong currentTime); 201 | }; 202 | 203 | } /* namespace naf */ 204 | } /* namespace efc */ 205 | 206 | #endif /* EIOSESSION_HH_ */ 207 | -------------------------------------------------------------------------------- /inc/ESocketAcceptor.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * ESocketAcceptor.hh 3 | * 4 | * Created on: 2013-8-19 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef ESOCKETACCEPTOR_HH_ 9 | #define ESOCKETACCEPTOR_HH_ 10 | 11 | #include "./EIoService.hh" 12 | #include "./ESocketSession.hh" 13 | #include "./EIoFilterChainBuilder.hh" 14 | 15 | namespace efc { 16 | namespace naf { 17 | 18 | class EManagedSession; 19 | 20 | /** 21 | * {@link IoAcceptor} for socket transport (TCP/IP). This class 22 | * handles incoming TCP/IP based socket connections. 23 | * 24 | */ 25 | 26 | class ESocketAcceptor: virtual public EIoService { 27 | public: 28 | enum Status { 29 | INITED, 30 | RUNNING, 31 | DISPOSING, 32 | DISPOSED 33 | }; 34 | 35 | class Service: public EObject { 36 | public: 37 | sp ss; 38 | boolean sslActive; 39 | EString serviceName; 40 | EInetSocketAddress boundAddress; 41 | virtual EString toString() { 42 | return boundAddress.toString() + ", ssl=" + sslActive + ", service=" + serviceName; 43 | } 44 | private: 45 | friend class ESocketAcceptor; 46 | Service(const char* name, boolean ssl, const char* hostname, int port) : 47 | sslActive(ssl), serviceName(name), boundAddress(hostname, port) { 48 | createSocket(); 49 | } 50 | Service(const char* name, boolean ssl, EInetSocketAddress* localAddress) : 51 | sslActive(ssl), serviceName(name), boundAddress(*localAddress) { 52 | createSocket(); 53 | } 54 | inline void createSocket() { 55 | if (sslActive) { 56 | ss = new ESSLServerSocket(); 57 | } else { 58 | ss = new EServerSocket(); 59 | } 60 | } 61 | }; 62 | 63 | public: 64 | virtual ~ESocketAcceptor(); 65 | 66 | ESocketAcceptor(); 67 | 68 | /** 69 | * 70 | */ 71 | EFiberScheduler& getFiberScheduler(); 72 | 73 | /** 74 | * @see ServerSocket#getReuseAddress() 75 | */ 76 | virtual boolean isReuseAddress(); 77 | 78 | /** 79 | * @see ServerSocket#setReuseAddress(boolean) 80 | */ 81 | virtual void setReuseAddress(boolean on); 82 | 83 | /** 84 | * Returns the size of the backlog. 85 | */ 86 | virtual int getBacklog(); 87 | 88 | /** 89 | * Sets the size of the backlog. This can only be done when this 90 | * class is not bound 91 | */ 92 | virtual void setBacklog(int backlog); 93 | 94 | /** 95 | * @see ServerSocket#setSoTimeout() 96 | */ 97 | virtual void setSoTimeout(int timeout) THROWS(ESocketException); 98 | 99 | /** 100 | * @see ServerSocket#getSoTimeout() 101 | */ 102 | virtual int getSoTimeout() THROWS(EIOException); 103 | 104 | /** 105 | * @see ServerSocket#setReceiveBufferSize() 106 | */ 107 | virtual void setReceiveBufferSize (int size) THROWS(ESocketException); 108 | 109 | /** 110 | * @see ServerSocket#getReceiveBufferSize() 111 | */ 112 | virtual int getReceiveBufferSize() THROWS(ESocketException); 113 | 114 | /** 115 | * 116 | */ 117 | virtual void setMaxConnections(int connections); 118 | 119 | /** 120 | * 121 | */ 122 | virtual int getMaxConnections(); 123 | 124 | /** 125 | * 126 | */ 127 | virtual void setSessionIdleTime(EIdleStatus status, int seconds); 128 | 129 | /** 130 | * 131 | */ 132 | virtual int getSessionIdleTime(EIdleStatus status); 133 | 134 | /** 135 | * 136 | */ 137 | virtual int getWorkThreads(); 138 | 139 | /** 140 | * 141 | */ 142 | virtual int getManagedSessionCount(); 143 | 144 | /** 145 | * 146 | */ 147 | virtual EIoFilterChainBuilder* getFilterChainBuilder(); 148 | 149 | /** 150 | * 151 | */ 152 | virtual EIoServiceStatistics* getStatistics(); 153 | 154 | /** 155 | * 156 | */ 157 | virtual void setListeningHandler(std::function handler); 158 | 159 | /** 160 | * 161 | */ 162 | virtual void setConnectionHandler(std::function& session, Service* service)> handler); 163 | 164 | /** 165 | * Binds the ServerSocket to a specific address 166 | * (IP address and port number). 167 | */ 168 | virtual void bind(int port, boolean ssl=false, const char* name=null, std::function listener=null) THROWS(EIOException); 169 | virtual void bind(const char* hostname, int port, boolean ssl=false, const char* name=null, std::function listener=null) THROWS(EIOException); 170 | virtual void bind(EInetSocketAddress *localAddress, boolean ssl=false, const char* name=null, std::function listener=null) THROWS(EIOException); 171 | virtual void bind(EIterable *localAddresses, boolean ssl=false, const char* name=null, std::function listener=null) THROWS(EIOException); 172 | 173 | /** 174 | * Listens for connections and loop run for network io events. 175 | */ 176 | virtual void listen() THROWS(EIOException); 177 | 178 | /** 179 | * Only close accept socket for gracefully stop. 180 | */ 181 | virtual void shutdown(); 182 | 183 | /** 184 | * Signal acceptor to stop immediately. 185 | */ 186 | virtual void dispose(); 187 | 188 | /** 189 | * Returns true if and if only all resources of this processor 190 | * have been disposed. 191 | */ 192 | virtual boolean isDisposed(); 193 | 194 | /** 195 | * 196 | */ 197 | virtual sp newSession(EIoService *service, sp& socket); 198 | 199 | protected: 200 | static sp logger; 201 | 202 | EFiberScheduler scheduler; 203 | 204 | EHashSet Services_; 205 | 206 | volatile Status status_;; 207 | boolean reuseAddress_;// = false; 208 | int backlog_; 209 | int timeout_; 210 | int bufsize_; 211 | EAtomicCounter maxConns_;// = -1; 212 | EAtomicCounter connections_; 213 | EAtomicCounter idleTimeForRead_; 214 | EAtomicCounter idleTimeForWrite_; 215 | 216 | int workThreads_; 217 | EManagedSession* managedSessions_; 218 | 219 | EIoFilterChainBuilder defaultFilterChain; 220 | 221 | EIoServiceStatistics stats_; 222 | 223 | std::function listeningCallback_; 224 | std::function& session, Service* service)> connectionCallback_; 225 | 226 | void startAccept(EFiberScheduler& scheduler, Service* service) THROWS(EIOException); 227 | void startClean(EFiberScheduler& scheduler, int tag) THROWS(EIOException); 228 | void startStatistics(EFiberScheduler& scheduler); 229 | void signalAccept(); 230 | 231 | virtual void onListeningHandle(); 232 | virtual void onConnectionHandle(sp& session, Service* service); 233 | }; 234 | 235 | } /* namespace naf */ 236 | } /* namespace efc */ 237 | 238 | #endif /* ESOCKETACCEPTOR_HH_ */ 239 | -------------------------------------------------------------------------------- /src/EHttpSession.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EHttpSession.cpp 3 | * 4 | * Created on: 2018-6-21 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EHttpSession.hh" 9 | #include "../inc/EHttpAcceptor.hh" 10 | 11 | #include "../http/source/enum_to_int.h" 12 | 13 | namespace efc { 14 | namespace naf { 15 | 16 | #define ARRLEN(x) (sizeof(x) / sizeof(x[0])) 17 | 18 | #define MAKE_NV(NAME, VALUE) \ 19 | { \ 20 | (uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \ 21 | NGHTTP2_NV_FLAG_NONE \ 22 | } 23 | 24 | sp ActiveStream::getHttpSession() { 25 | return dynamic_pointer_cast(session->shared_from_this()); 26 | } 27 | 28 | void ActiveStream::decode100ContinueHeaders(HeaderMapPtr&& headers) { 29 | // ignore for client request. 30 | ES_ASSERT(0); 31 | } 32 | 33 | //@see: envoy-1.6.0/source/common/http/conn_manager_impl.cc::decodeHeaders(...) 34 | void ActiveStream::decodeHeaders(HeaderMapPtr&& headers, bool end_stream) { 35 | // printf("decodeHeaders\n"); 36 | 37 | // Check for maximum incoming header size. Both codecs have some amount of checking for maximum 38 | // header size. For HTTP/1.1 the entire headers data has be less than ~80K (hard coded in 39 | // http_parser). For HTTP/2 the default allowed header block length is 64k. 40 | // In order to have generally uniform behavior we also check total header size here and keep it 41 | // under 60K. Ultimately it would be nice to have a configuration option ranging from the largest 42 | // header size http_parser and nghttp2 will allow, down to 16k or 8k for 43 | // envoy users who do not wish to proxy large headers. 44 | if (headers->byteSize() > (60 * 1024)) { 45 | HeaderMapImpl headers{ 46 | {Headers::get().Status, std::to_string(enumToInt(Code::RequestHeaderFieldsTooLarge))}}; 47 | response_encoder->encodeHeaders(headers, true); 48 | return; 49 | } 50 | 51 | // Currently we only support relative paths at the application layer. We expect the codec to have 52 | // broken the path into pieces if applicable. NOTE: Currently the HTTP/1.1 codec does not do this 53 | // so we only support relative paths in all cases. https://tools.ietf.org/html/rfc7230#section-5.3 54 | // We also need to check for the existence of :path because CONNECT does not have a path, and we 55 | // don't support that currently. 56 | if (!headers->Path() || headers->Path()->value().c_str()[0] != '/') { 57 | HeaderMapImpl headers{{Headers::get().Status, std::to_string(enumToInt(Code::NotFound))}}; 58 | response_encoder->encodeHeaders(headers, true); 59 | return; 60 | } 61 | 62 | // Create a new http request. 63 | request = new EHttpRequest(this, headers); 64 | if (end_stream) { 65 | session->getHttpAcceptor()->requestChannel.write(request); 66 | } 67 | } 68 | 69 | void ActiveStream::decodeData(Buffer::Instance& data, bool end_stream) { 70 | // printf("decodeData(), data.length=%llu\n", data.length()); 71 | 72 | ES_ASSERT(request != null && request->getHttpStream() == this); 73 | 74 | Http::Buffer::OwnedImpl& oi = dynamic_cast(data); 75 | Http::Buffer::LinkedBuffer& lb = oi.buffer(); 76 | 77 | for (auto buffer : lb) { 78 | request->bodyData.add(buffer); 79 | } 80 | 81 | if (end_stream) { 82 | session->getHttpAcceptor()->requestChannel.write(request); 83 | } 84 | } 85 | 86 | void ActiveStream::decodeTrailers(HeaderMapPtr&& trailers) { 87 | // ignore for client request. 88 | ES_ASSERT(0); 89 | } 90 | 91 | void ActiveStream::encode100ContinueHeaders(const HeaderMap& headers) { 92 | response_encoder->encode100ContinueHeaders(headers); 93 | } 94 | 95 | void ActiveStream::encodeHeaders(const HeaderMap& headers, bool end_stream) { 96 | response_encoder->encodeHeaders(headers, end_stream); 97 | } 98 | 99 | void ActiveStream::encodeData(Buffer::Instance& data, bool end_stream) { 100 | response_encoder->encodeData(data, end_stream); 101 | } 102 | 103 | void ActiveStream::encodeTrailers(const HeaderMap& trailers) { 104 | response_encoder->encodeTrailers(trailers); 105 | } 106 | 107 | //============================================================================= 108 | 109 | EHttpSession::~EHttpSession() { 110 | // 111 | } 112 | 113 | EHttpSession::EHttpSession(EIoService* service, sp& socket) : 114 | ESocketSession(service, socket), isFirstRequest(true) { 115 | acceptor = dynamic_cast(service); 116 | } 117 | 118 | EHttpAcceptor* EHttpSession::getHttpAcceptor() { 119 | return acceptor; 120 | } 121 | 122 | void EHttpSession::init() { 123 | // 124 | } 125 | 126 | sp EHttpSession::read() { 127 | sp ioBuffer = dynamic_pointer_cast(ESocketSession::read()); 128 | if (ioBuffer != null) { 129 | if (isFirstRequest) { 130 | int magic_len = strlen(NGHTTP2_CLIENT_MAGIC); 131 | sp buf; 132 | if (firstRequestBuffer == null) { 133 | if (ioBuffer->remaining() < magic_len) { 134 | firstRequestBuffer = new EByteBuffer(32); 135 | firstRequestBuffer->append(ioBuffer->current(), ioBuffer->remaining()); 136 | buf = EIoBuffer::wrap(firstRequestBuffer->data(), firstRequestBuffer->size()); 137 | } else { 138 | buf = ioBuffer; 139 | } 140 | } else { 141 | firstRequestBuffer->append(ioBuffer->current(), ioBuffer->remaining()); 142 | buf = EIoBuffer::wrap(firstRequestBuffer->data(), firstRequestBuffer->size()); 143 | } 144 | 145 | if (buf->remaining() >= magic_len) { 146 | sp session = dynamic_pointer_cast(shared_from_this()); 147 | 148 | if (memcmp(buf->current(), NGHTTP2_CLIENT_MAGIC, magic_len) != 0) { 149 | codec_.reset(new Http::Http1::ServerConnectionImpl(session, *this, hs1)); 150 | } else { 151 | codec_.reset(new Http::Http2::ServerConnectionImpl(session, *this, hs2)); 152 | } 153 | codec_->dispatch(buf); 154 | isFirstRequest = false; 155 | firstRequestBuffer = null; 156 | } 157 | } else { 158 | codec_->dispatch(ioBuffer); 159 | } 160 | } 161 | return ioBuffer; 162 | } 163 | 164 | boolean EHttpSession::write(sp message) { 165 | return ESocketSession::write(message); 166 | } 167 | 168 | void EHttpSession::close() { 169 | responseChannel.write(new EndHttpResponse()); 170 | ESocketSession::close(); 171 | } 172 | 173 | Http::StreamDecoder& EHttpSession::newStream(Http::StreamEncoder& response_encoder) { 174 | ActiveStream* stream = new ActiveStream(this, response_encoder); 175 | streams_.add(stream); 176 | return *stream; 177 | } 178 | 179 | void EHttpSession::onGoAway() { 180 | // 181 | } 182 | } /* namespace naf */ 183 | } /* namespace efc */ 184 | -------------------------------------------------------------------------------- /test/testnaf.cpp: -------------------------------------------------------------------------------- 1 | #include "es_main.h" 2 | #include "ENaf.hh" 3 | 4 | #include "http_parser/http_parser.h" 5 | 6 | #include "../filter/http/EHttpCodecFilter.hh" 7 | #include "../filter/http/EHttpRequest.hh" 8 | #include "../filter/http/EHttpResponse.hh" 9 | 10 | using namespace filter::http; 11 | 12 | #define LOG(fmt,...) ESystem::out->printfln(fmt, ##__VA_ARGS__) 13 | 14 | #define SSL_FILE_PATH "" 15 | 16 | #define USE_HTTP_FILTER 1 17 | #define PRINT_STATISTICS 0 18 | 19 | static ESocketAcceptor g_sa; 20 | 21 | static void onListening(ESocketAcceptor* acceptor) { 22 | LOG("onListening..."); 23 | 24 | #if PRINT_STATISTICS 25 | while (!acceptor->isDisposed()) { 26 | sleep(10); 27 | 28 | EIoServiceStatistics* ss = acceptor->getStatistics(); 29 | LOG("CumulativeManagedSessionCount=%ld", ss->getCumulativeManagedSessionCount()); 30 | LOG("LargestManagedSessionCount=%ld", ss->getLargestManagedSessionCount()); 31 | LOG("LargestReadBytesThroughput=%lf", ss->getLargestReadBytesThroughput()); 32 | LOG("LargestReadMessagesThroughput=%lf", ss->getLargestReadMessagesThroughput()); 33 | LOG("LargestWrittenBytesThroughput=%lf", ss->getLargestWrittenBytesThroughput()); 34 | LOG("getLargestWrittenMessagesThroughput=%lf", ss->getLargestWrittenMessagesThroughput()); 35 | LOG("LastIoTime=%ld", ss->getLastIoTime()); 36 | LOG("LastReadTime=%ld", ss->getLastReadTime()); 37 | LOG("LastWriteTime=%ld", ss->getLastWriteTime()); 38 | LOG("ReadBytes=%ld", ss->getReadBytes()); 39 | LOG("ReadBytesThroughput=%lf", ss->getReadBytesThroughput()); 40 | LOG("ReadMessages=%ld", ss->getReadMessages()); 41 | LOG("ReadMessagesThroughput=%lf", ss->getReadMessagesThroughput()); 42 | LOG("WrittenBytes=%ld", ss->getWrittenBytes()); 43 | LOG("WrittenBytesThroughput=%lf", ss->getWrittenBytesThroughput()); 44 | LOG("WrittenMessages=%ld", ss->getWrittenMessages()); 45 | LOG("WrittenMessagesThroughput=%lf", ss->getWrittenMessagesThroughput()); 46 | LOG("\n"); 47 | } 48 | #endif 49 | } 50 | 51 | #if USE_HTTP_FILTER 52 | static void onConnection(sp& session, ESocketAcceptor::Service* service) { 53 | LOG("onConnection: service=%s", service->toString().c_str()); 54 | 55 | // sleep(10); 56 | 57 | sp request; 58 | while ((request = dynamic_pointer_cast(session->read())) != null) { 59 | LOG("%.*s", request->getBodyLen()+request->getHeadLen(), request->getHttpData()); 60 | 61 | session->write(new EHttpResponse("OK")); // send text. 62 | // session->write(new EFile("xxx.zip")); // send file. 63 | 64 | // break; 65 | } 66 | 67 | LOG("Out of Connection."); 68 | } 69 | #else 70 | 71 | static int on_info(http_parser* p) { 72 | return 0; 73 | } 74 | 75 | static int on_message_complete(http_parser* p) { 76 | ESocketSession* session = (ESocketSession*)p->data; 77 | 78 | sp response(EIoBuffer::allocate(256)->setAutoExpand(true)); 79 | #define TEST_HTTP_DATA "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nOK!" 80 | response->putString(TEST_HTTP_DATA); 81 | response->flip(); 82 | session->write(response); 83 | 84 | return 0; 85 | } 86 | 87 | static int on_data(http_parser* p, const char *at, size_t length) { 88 | return 0; 89 | } 90 | 91 | static int on_body(http_parser* p, const char *at, size_t length) { 92 | LOG("%.*s", length, at); 93 | return 0; 94 | } 95 | 96 | static http_parser_settings settings = { 97 | .on_message_begin = on_info, 98 | .on_headers_complete = on_info, 99 | .on_message_complete = on_message_complete, 100 | .on_header_field = on_data, 101 | .on_header_value = on_data, 102 | .on_url = on_data, 103 | .on_status = on_data, 104 | .on_body = on_body 105 | }; 106 | 107 | static void onConnection(sp& session, ESocketAcceptor::Service* service) { 108 | LOG("onConnection..."); 109 | 110 | struct http_parser parser; 111 | http_parser_init(&parser, HTTP_REQUEST); 112 | 113 | sp request; 114 | while(!session->getService()->isDisposed()) { 115 | try { 116 | request = dynamic_pointer_cast(session->read()); 117 | } catch (ESocketTimeoutException& e) { 118 | LOG("session read timeout."); 119 | continue; 120 | } catch (EIOException& e) { 121 | LOG("session read error."); 122 | break; 123 | } 124 | if (request == null) { 125 | LOG("session client closed."); 126 | break; 127 | } 128 | 129 | parser.data = session.get(); 130 | 131 | size_t parsed = http_parser_execute(&parser, &settings, (const char *)request->current(), request->limit()); 132 | if (parsed != request->limit()) { 133 | throw EIOException(__FILE__, __LINE__, "Not http data."); 134 | } 135 | LOG("%s", request->getString().c_str()); 136 | } 137 | 138 | LOG("Out of Connection."); 139 | } 140 | #endif 141 | 142 | static void test_echo_server() { 143 | EBlacklistFilter blf; 144 | EWhitelistFilter wlf; 145 | blf.block("localhost"); 146 | // g_sa.getFilterChainBuilder()->addFirst("black", &blf); 147 | wlf.allow("localhost"); 148 | // g_sa.getFilterChainBuilder()->addFirst("white", &wlf); 149 | #if USE_HTTP_FILTER 150 | EHttpCodecFilter hcf; 151 | g_sa.getFilterChainBuilder()->addLast("http", &hcf); 152 | #endif 153 | g_sa.setListeningHandler(onListening); 154 | g_sa.setConnectionHandler(onConnection); 155 | // sa.setMaxConnections(10); 156 | g_sa.setSoTimeout(30000); 157 | g_sa.setSessionIdleTime(EIdleStatus::WRITER_IDLE, 30); 158 | g_sa.bind("0.0.0.0", 8887, false, "serviceA"); 159 | g_sa.bind("localhost", 8889, true, "serviceB", [](ESocketAcceptor::Service& service){ 160 | LOG("service [%s] is active.", service.toString().c_str()); 161 | 162 | if (service.sslActive) { 163 | sp sss = dynamic_pointer_cast(service.ss); 164 | sss->setSSLParameters( 165 | "./certs/tests-cert.pem", 166 | "./certs/tests-key.pem", 167 | null); 168 | } 169 | }); 170 | g_sa.listen(); 171 | } 172 | 173 | static void test_test(int argc, const char** argv) { 174 | test_echo_server(); 175 | } 176 | 177 | static void sigfunc(int sig_no) { 178 | /** 179 | * signal handler is running in main thread!!! 180 | */ 181 | LOG("signaled."); 182 | g_sa.shutdown(); 183 | } 184 | 185 | MAIN_IMPL(testnaf) { 186 | printf("main()\n"); 187 | 188 | ESystem::init(argc, argv); 189 | ELoggerManager::init("log4e.conf"); 190 | 191 | signal(SIGINT, sigfunc); 192 | 193 | printf("inited.\n"); 194 | 195 | int i = 0; 196 | try { 197 | boolean loop = EBoolean::parseBoolean(ESystem::getProgramArgument("loop")); 198 | do { 199 | test_test(argc, argv); 200 | 201 | // } while (++i < 5); 202 | } while (0); 203 | } 204 | catch (EException& e) { 205 | e.printStackTrace(); 206 | } 207 | catch (...) { 208 | printf("catch all...\n"); 209 | } 210 | 211 | printf("exit...\n"); 212 | 213 | ESystem::exit(0); 214 | 215 | return 0; 216 | } 217 | -------------------------------------------------------------------------------- /http/source/utility.cc: -------------------------------------------------------------------------------- 1 | #include "./utility.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "./exception.h" 11 | 12 | namespace efc { 13 | namespace naf { 14 | namespace Http { 15 | 16 | std::string DateFormatter::fromTime(const SystemTime& time) { 17 | return fromTimeT(std::chrono::system_clock::to_time_t(time)); 18 | } 19 | 20 | std::string DateFormatter::fromTimeT(time_t time) { 21 | tm current_tm; 22 | gmtime_r(&time, ¤t_tm); 23 | 24 | std::array buf; 25 | strftime(&buf[0], buf.size(), format_string_.c_str(), ¤t_tm); 26 | return std::string(&buf[0]); 27 | } 28 | 29 | std::string DateFormatter::now() { 30 | time_t current_time_t; 31 | time(¤t_time_t); 32 | return fromTimeT(current_time_t); 33 | } 34 | 35 | ProdSystemTimeSource ProdSystemTimeSource::instance_; 36 | ProdMonotonicTimeSource ProdMonotonicTimeSource::instance_; 37 | 38 | ConstMemoryStreamBuffer::ConstMemoryStreamBuffer(const char* data, 39 | size_t size) { 40 | // std::streambuf won't modify `data`, but the interface still requires a char* for convenience, 41 | // so we need to const_cast. 42 | char* ptr = const_cast(data); 43 | 44 | this->setg(ptr, ptr, ptr + size); 45 | } 46 | 47 | InputConstMemoryStream::InputConstMemoryStream(const char* data, size_t size) : 48 | ConstMemoryStreamBuffer { data, size }, std::istream { 49 | static_cast(this) } { 50 | } 51 | 52 | bool DateUtil::timePointValid(SystemTime time_point) { 53 | return std::chrono::duration_cast( 54 | time_point.time_since_epoch()).count() != 0; 55 | } 56 | 57 | bool DateUtil::timePointValid(MonotonicTime time_point) { 58 | return std::chrono::duration_cast( 59 | time_point.time_since_epoch()).count() != 0; 60 | } 61 | 62 | const char StringUtil::WhitespaceChars[] = " \t\f\v\n\r"; 63 | 64 | bool StringUtil::atoul(const char* str, uint64_t& out, int base) { 65 | if (strlen(str) == 0) { 66 | return false; 67 | } 68 | 69 | char* end_ptr; 70 | errno = 0; 71 | out = strtoul(str, &end_ptr, base); 72 | if (*end_ptr != '\0' || (out == ULONG_MAX && errno == ERANGE)) { 73 | return false; 74 | } else { 75 | return true; 76 | } 77 | } 78 | 79 | bool StringUtil::atol(const char* str, int64_t& out, int base) { 80 | if (strlen(str) == 0) { 81 | return false; 82 | } 83 | 84 | char* end_ptr; 85 | errno = 0; 86 | out = strtol(str, &end_ptr, base); 87 | if (*end_ptr != '\0' 88 | || ((out == LONG_MAX || out == LONG_MIN) && errno == ERANGE)) { 89 | return false; 90 | } else { 91 | return true; 92 | } 93 | } 94 | 95 | uint32_t StringUtil::itoa(char* out, size_t buffer_size, uint64_t i) { 96 | // The maximum size required for an unsigned 64-bit integer is 21 chars (including null). 97 | if (buffer_size < 21) { 98 | throw std::invalid_argument("itoa buffer too small"); 99 | } 100 | 101 | char* current = out; 102 | do { 103 | *current++ = "0123456789"[i % 10]; 104 | i /= 10; 105 | } while (i > 0); 106 | 107 | for (uint64_t i = 0, j = current - out - 1; i < j; i++, j--) { 108 | char c = out[i]; 109 | out[i] = out[j]; 110 | out[j] = c; 111 | } 112 | 113 | *current = 0; 114 | return current - out; 115 | } 116 | 117 | size_t StringUtil::strlcpy(char* dst, const char* src, size_t size) { 118 | strncpy(dst, src, size - 1); 119 | dst[size - 1] = '\0'; 120 | return strlen(src); 121 | } 122 | 123 | std::string StringUtil::join(const std::vector& source, 124 | const std::string& delimiter) { 125 | std::ostringstream buf; 126 | std::copy(source.begin(), source.end(), 127 | std::ostream_iterator(buf, delimiter.c_str())); 128 | std::string ret = buf.str(); 129 | // copy will always end with an extra delimiter, we remove it here. 130 | return ret.substr(0, ret.length() - delimiter.length()); 131 | } 132 | 133 | std::string StringUtil::subspan(const std::string& source, size_t start, 134 | size_t end) { 135 | return source.substr(start, end - start); 136 | } 137 | 138 | std::string StringUtil::escape(const std::string& source) { 139 | std::string ret; 140 | 141 | // Prevent unnecessary allocation by allocating 2x original size. 142 | ret.reserve(source.length() * 2); 143 | for (char c : source) { 144 | switch (c) { 145 | case '\r': 146 | ret += "\\r"; 147 | break; 148 | case '\n': 149 | ret += "\\n"; 150 | break; 151 | case '\t': 152 | ret += "\\t"; 153 | break; 154 | case '"': 155 | ret += "\\\""; 156 | break; 157 | default: 158 | ret += c; 159 | break; 160 | } 161 | } 162 | 163 | return ret; 164 | } 165 | 166 | bool StringUtil::endsWith(const std::string& source, const std::string& end) { 167 | if (source.length() < end.length()) { 168 | return false; 169 | } 170 | 171 | size_t start_position = source.length() - end.length(); 172 | return std::equal(source.begin() + start_position, source.end(), 173 | end.begin()); 174 | } 175 | 176 | bool StringUtil::startsWith(const char* source, const std::string& start, 177 | bool case_sensitive) { 178 | if (case_sensitive) { 179 | return strncmp(source, start.c_str(), start.size()) == 0; 180 | } else { 181 | return strncasecmp(source, start.c_str(), start.size()) == 0; 182 | } 183 | } 184 | 185 | const std::string& StringUtil::nonEmptyStringOrDefault(const std::string& s, 186 | const std::string& default_value) { 187 | return s.empty() ? default_value : s; 188 | } 189 | 190 | bool Primes::isPrime(uint32_t x) { 191 | if (x < 4) { 192 | return true; // eliminates special-casing 2. 193 | } else if ((x & 1) == 0) { 194 | return false; // eliminates even numbers >2. 195 | } 196 | 197 | uint32_t limit = sqrt(x); 198 | for (uint32_t factor = 3; factor <= limit; factor += 2) { 199 | if ((x % factor) == 0) { 200 | return false; 201 | } 202 | } 203 | return true; 204 | } 205 | 206 | uint32_t Primes::findPrimeLargerThan(uint32_t x) { 207 | x += (x % 2) + 1; 208 | while (!isPrime(x)) { 209 | x += 2; 210 | } 211 | return x; 212 | } 213 | 214 | // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm 215 | void WelfordStandardDeviation::update(double newValue) { 216 | ++count_; 217 | const double delta = newValue - mean_; 218 | mean_ += delta / count_; 219 | const double delta2 = newValue - mean_; 220 | m2_ += delta * delta2; 221 | } 222 | 223 | double WelfordStandardDeviation::computeVariance() const { 224 | if (count_ < 2) { 225 | return std::nan(""); 226 | } 227 | return m2_ / (count_ - 1); 228 | } 229 | 230 | double WelfordStandardDeviation::computeStandardDeviation() const { 231 | const double variance = computeVariance(); 232 | // It seems very difficult for variance to go negative, but from the calculation in update() 233 | // above, I can't quite convince myself it's impossible, so put in a guard to be sure. 234 | return (std::isnan(variance) || variance < 0) ? 235 | std::nan("") : sqrt(variance); 236 | } 237 | 238 | } // namespace Http 239 | } // namespace naf 240 | } // namespace efc 241 | -------------------------------------------------------------------------------- /src/EIoFilterChainBuidler.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoFilterChainBuilder.cpp 3 | * 4 | * Created on: 2017-3-16 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EIoFilterChainBuilder.hh" 9 | 10 | namespace efc { 11 | namespace naf { 12 | 13 | class EntryImpl : public EIoFilterChain::Entry { 14 | public: 15 | EString name; 16 | EIoFilter* volatile filter; 17 | EIoFilterChainBuilder* owner; 18 | 19 | virtual ~EntryImpl() { 20 | //TODO... 21 | } 22 | 23 | EntryImpl(const char* name, EIoFilter* filter, EIoFilterChainBuilder* dicb) { 24 | if (name == null) { 25 | throw EIllegalArgumentException(__FILE__, __LINE__, "name"); 26 | } 27 | if (filter == null) { 28 | throw EIllegalArgumentException(__FILE__, __LINE__, "filter"); 29 | } 30 | 31 | this->name = name; 32 | this->filter = filter; 33 | this->owner = dicb; 34 | } 35 | 36 | const char* getName() { 37 | return name.c_str(); 38 | } 39 | 40 | EIoFilter* getFilter() { 41 | return filter; 42 | } 43 | 44 | void setFilter(EIoFilter* filter) { 45 | this->filter = filter; 46 | } 47 | 48 | EIoFilter::NextFilter* getNextFilter() { 49 | throw EIllegalStateException(__FILE__, __LINE__); 50 | } 51 | 52 | virtual EString toString() { 53 | return EString::formatOf("(%s:%s)", name.c_str(), filter->toString().c_str()); 54 | } 55 | 56 | void addAfter(const char* name, EIoFilter* filter) { 57 | owner->addAfter(getName(), name, filter); 58 | } 59 | 60 | void addBefore(const char* name, EIoFilter* filter) { 61 | owner->addBefore(getName(), name, filter); 62 | } 63 | 64 | void remove() { 65 | owner->remove(getName()); 66 | } 67 | 68 | // void replace(EIoFilter* newFilter) { 69 | // owner->replace(getName(), newFilter); 70 | // } 71 | }; 72 | 73 | EIoFilterChainBuilder::~EIoFilterChainBuilder() { 74 | 75 | } 76 | 77 | EIoFilterChainBuilder::EIoFilterChainBuilder() { 78 | 79 | } 80 | 81 | EIoFilterChain::Entry* EIoFilterChainBuilder::getEntry( 82 | const char* name) { 83 | sp > > citer = entries.iterator(); 84 | while (citer->hasNext()) { 85 | sp e = citer->next(); 86 | EString n(e->getName()); 87 | if (n.equals(name)) { 88 | return e.get(); 89 | } 90 | } 91 | 92 | return null; 93 | } 94 | 95 | EIoFilterChain::Entry* EIoFilterChainBuilder::getEntry( 96 | EIoFilter* filter) { 97 | sp > > citer = entries.iterator(); 98 | while (citer->hasNext()) { 99 | sp e = citer->next(); 100 | if (e->getFilter() == filter) { 101 | return e.get(); 102 | } 103 | } 104 | 105 | return null; 106 | } 107 | 108 | EIoFilter* EIoFilterChainBuilder::get(const char* name) { 109 | sp e = getEntry(name); 110 | if (e == null) { 111 | return null; 112 | } 113 | 114 | return e->getFilter(); 115 | } 116 | 117 | boolean EIoFilterChainBuilder::contains(const char* name) { 118 | return getEntry(name) != null; 119 | } 120 | 121 | boolean EIoFilterChainBuilder::contains(EIoFilter* filter) { 122 | return getEntry(filter) != null; 123 | } 124 | 125 | void EIoFilterChainBuilder::addFirst(const char* name, EIoFilter* filter) { 126 | register_(0, new EntryImpl(name, filter, this)); 127 | } 128 | 129 | void EIoFilterChainBuilder::addLast(const char* name, EIoFilter* filter) { 130 | register_(entries.size(), new EntryImpl(name, filter, this)); 131 | } 132 | 133 | void EIoFilterChainBuilder::addBefore(const char* baseName, const char* name, 134 | EIoFilter* filter) { 135 | checkBaseName(baseName); 136 | 137 | for (sp > > i = entries.listIterator(); i->hasNext();) { 138 | sp base = i->next(); 139 | if (strcmp(base->getName(), baseName) == 0) { 140 | register_(i->previousIndex(), new EntryImpl(name, filter, this)); 141 | break; 142 | } 143 | } 144 | } 145 | 146 | void EIoFilterChainBuilder::addAfter(const char* baseName, const char* name, 147 | EIoFilter* filter) { 148 | checkBaseName(baseName); 149 | 150 | for (sp > > i = entries.listIterator(); i->hasNext();) { 151 | sp base = i->next(); 152 | if (strcmp(base->getName(), baseName) == 0) { 153 | register_(i->nextIndex(), new EntryImpl(name, filter, this)); 154 | break; 155 | } 156 | } 157 | } 158 | 159 | EIoFilter* EIoFilterChainBuilder::remove(const char* name) { 160 | if (name == null) { 161 | throw EIllegalArgumentException(__FILE__, __LINE__, "name"); 162 | } 163 | 164 | for (sp > > i = entries.listIterator(); i->hasNext();) { 165 | sp e = i->next(); 166 | if (strcmp(e->getName(), name) == 0) { 167 | entries.removeAt(i->previousIndex()); 168 | return e->getFilter(); 169 | } 170 | } 171 | 172 | EString msg("Unknown filter name: "); 173 | msg += name; 174 | throw EIllegalArgumentException(__FILE__, __LINE__, msg.c_str()); 175 | } 176 | 177 | EIoFilter* EIoFilterChainBuilder::remove(EIoFilter* filter) { 178 | if (filter == null) { 179 | throw EIllegalArgumentException(__FILE__, __LINE__, "filter"); 180 | } 181 | 182 | for (sp > > i = entries.listIterator(); i->hasNext();) { 183 | sp e = i->next(); 184 | if (e->getFilter() == filter) { 185 | entries.removeAt(i->previousIndex()); 186 | return e->getFilter(); 187 | } 188 | } 189 | 190 | EString msg("Filter not found: "); 191 | msg += filter->toString(); 192 | throw EIllegalArgumentException(__FILE__, __LINE__, msg.c_str()); 193 | } 194 | 195 | void EIoFilterChainBuilder::clear() { 196 | entries.clear(); 197 | } 198 | 199 | void EIoFilterChainBuilder::buildFilterChain(EIoFilterChain* chain) { 200 | sp > > citer = entries.iterator(); 201 | while (citer->hasNext()) { 202 | sp e = citer->next(); 203 | chain->addLast(e->getName(), e->getFilter()); 204 | } 205 | } 206 | 207 | EString EIoFilterChainBuilder::toString() { 208 | EString buf("{ "); 209 | 210 | boolean empty = true; 211 | 212 | sp > > citer = entries.iterator(); 213 | while (citer->hasNext()) { 214 | sp e = citer->next(); 215 | if (!empty) { 216 | buf.append(", "); 217 | } else { 218 | empty = false; 219 | } 220 | 221 | buf.append('('); 222 | buf.append(e->getName()); 223 | buf.append(':'); 224 | buf.append(e->getFilter()->toString()); 225 | buf.append(')'); 226 | } 227 | 228 | if (empty) { 229 | buf.append("empty"); 230 | } 231 | 232 | buf.append(" }"); 233 | 234 | return buf; 235 | } 236 | 237 | void EIoFilterChainBuilder::register_(int index, EIoFilterChain::Entry* e) { 238 | if (contains(e->getName())) { 239 | throw EIllegalArgumentException(__FILE__, __LINE__, "Other filter is using the same name."); 240 | } 241 | 242 | entries.addAt(index, e); 243 | } 244 | 245 | void EIoFilterChainBuilder::checkBaseName(const char* baseName) { 246 | if (baseName == null) { 247 | throw EIllegalArgumentException(__FILE__, __LINE__, "baseName"); 248 | } 249 | 250 | if (!contains(baseName)) { 251 | EString msg("Unknown filter name: "); 252 | msg += baseName; 253 | throw EIllegalArgumentException(__FILE__, __LINE__, msg.c_str()); 254 | } 255 | } 256 | 257 | } /* namespace naf */ 258 | } /* namespace efc */ 259 | -------------------------------------------------------------------------------- /http/source/utility.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "./time.h" 15 | 16 | namespace efc { 17 | namespace naf { 18 | namespace Http { 19 | 20 | /** 21 | * Utility class for formatting dates given a strftime style format string. 22 | */ 23 | class DateFormatter { 24 | public: 25 | DateFormatter(const std::string& format_string) : 26 | format_string_(format_string) { 27 | } 28 | 29 | /** 30 | * @return std::string representing the GMT/UTC time based on the input time. 31 | */ 32 | std::string fromTime(const SystemTime& time); 33 | 34 | /** 35 | * @return std::string representing the current GMT/UTC time based on the format string. 36 | */ 37 | std::string now(); 38 | 39 | private: 40 | std::string fromTimeT(time_t time); 41 | 42 | std::string format_string_; 43 | }; 44 | 45 | /** 46 | * Production implementation of SystemTimeSource that returns the current time. 47 | */ 48 | class ProdSystemTimeSource: public SystemTimeSource { 49 | public: 50 | // SystemTimeSource 51 | SystemTime currentTime() override {return std::chrono::system_clock::now();} 52 | 53 | static ProdSystemTimeSource instance_; 54 | }; 55 | 56 | /** 57 | * Production implementation of MonotonicTimeSource that returns the current time. 58 | */ 59 | class ProdMonotonicTimeSource: public MonotonicTimeSource { 60 | public: 61 | // MonotonicTimeSource 62 | MonotonicTime currentTime() override {return std::chrono::steady_clock::now();} 63 | 64 | static ProdMonotonicTimeSource instance_; 65 | }; 66 | 67 | /** 68 | * Class used for creating non-copying std::istream's. See InputConstMemoryStream below. 69 | */ 70 | class ConstMemoryStreamBuffer: public std::streambuf { 71 | public: 72 | ConstMemoryStreamBuffer(const char* data, size_t size); 73 | }; 74 | 75 | /** 76 | * std::istream class similar to std::istringstream, except that it provides a view into a region of 77 | * constant memory. It can be more efficient than std::istringstream because it doesn't copy the 78 | * provided string. 79 | * 80 | * See https://stackoverflow.com/a/13059195/4447365. 81 | */ 82 | class InputConstMemoryStream: public virtual ConstMemoryStreamBuffer, 83 | public std::istream { 84 | public: 85 | InputConstMemoryStream(const char* data, size_t size); 86 | }; 87 | 88 | /** 89 | * Utility class for date/time helpers. 90 | */ 91 | class DateUtil { 92 | public: 93 | /** 94 | * @return whether a time_point contains a valid, not default constructed time. 95 | */ 96 | static bool timePointValid(SystemTime time_point); 97 | 98 | /** 99 | * @return whether a time_point contains a valid, not default constructed time. 100 | */ 101 | static bool timePointValid(MonotonicTime time_point); 102 | }; 103 | 104 | /** 105 | * Utility routines for working with strings. 106 | */ 107 | class StringUtil { 108 | public: 109 | static const char WhitespaceChars[]; 110 | 111 | /** 112 | * Convert a string to an unsigned long, checking for error. 113 | * @param return true if successful, false otherwise. 114 | */ 115 | static bool atoul(const char* str, uint64_t& out, int base = 10); 116 | 117 | /** 118 | * Convert a string to a long, checking for error. 119 | * @param return true if successful, false otherwise. 120 | */ 121 | static bool atol(const char* str, int64_t& out, int base = 10); 122 | 123 | /** 124 | * Perform a case insensitive compare of 2 strings. 125 | * @param lhs supplies string 1. 126 | * @param rhs supplies string 2. 127 | * @return < 0, 0, > 0 depending on the comparison result. 128 | */ 129 | static int caseInsensitiveCompare(const char* lhs, const char* rhs) { 130 | return strcasecmp(lhs, rhs); 131 | } 132 | 133 | /** 134 | * Convert an unsigned integer to a base 10 string as fast as possible. 135 | * @param out supplies the string to fill. 136 | * @param out_len supplies the length of the output buffer. Must be >= MIN_ITOA_OUT_LEN. 137 | * @param i supplies the number to convert. 138 | * @return the size of the string, not including the null termination. 139 | */ 140 | static constexpr size_t MIN_ITOA_OUT_LEN = 21; 141 | static uint32_t itoa(char* out, size_t out_len, uint64_t i); 142 | 143 | /** 144 | * Size-bounded string copying and concatenation 145 | */ 146 | static size_t strlcpy(char* dst, const char* src, size_t size); 147 | 148 | /** 149 | * Join elements of a vector into a string delimited by delimiter. 150 | * @param source supplies the strings to join. 151 | * @param delimiter supplies the delimiter to join them together. 152 | * @return string combining elements of `source` with `delimiter` in between each element. 153 | */ 154 | static std::string join(const std::vector& source, 155 | const std::string& delimiter); 156 | 157 | /** 158 | * Version of substr() that operates on a start and end index instead of a start index and a 159 | * length. 160 | */ 161 | static std::string subspan(const std::string& source, size_t start, 162 | size_t end); 163 | 164 | /** 165 | * Escape strings for logging purposes. Returns a copy of the string with 166 | * \n, \r, \t, and " (double quote) escaped. 167 | * @param source supplies the string to escape. 168 | * @return escaped string. 169 | */ 170 | static std::string escape(const std::string& source); 171 | 172 | /** 173 | * @return true if @param source ends with @param end. 174 | */ 175 | static bool endsWith(const std::string& source, const std::string& end); 176 | 177 | /** 178 | * @param case_sensitive determines if the compare is case sensitive 179 | * @return true if @param source starts with @param start and ignores cases. 180 | */ 181 | static bool startsWith(const char* source, const std::string& start, 182 | bool case_sensitive = true); 183 | 184 | /** 185 | * Provide a default value for a string if empty. 186 | * @param s string. 187 | * @param default_value replacement for s if empty. 188 | * @return s is !s.empty() otherwise default_value. 189 | */ 190 | static const std::string& nonEmptyStringOrDefault(const std::string& s, 191 | const std::string& default_value); 192 | }; 193 | 194 | /** 195 | * Utilities for finding primes 196 | */ 197 | class Primes { 198 | public: 199 | /** 200 | * Determines whether x is prime. 201 | */ 202 | static bool isPrime(uint32_t x); 203 | 204 | /** 205 | * Finds the next prime number larger than x. 206 | */ 207 | static uint32_t findPrimeLargerThan(uint32_t x); 208 | }; 209 | 210 | /** 211 | * Computes running standard-deviation using Welford's algorithm: 212 | * https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm 213 | */ 214 | class WelfordStandardDeviation { 215 | public: 216 | /** 217 | * Accumulates a new value into the standard deviation. 218 | * @param newValue the new value 219 | */ 220 | void update(double newValue); 221 | 222 | /** 223 | * @return double the computed mean value. 224 | */ 225 | double mean() const { 226 | return mean_; 227 | } 228 | 229 | /** 230 | * @return uint64_t the number of times update() was called 231 | */ 232 | uint64_t count() const { 233 | return count_; 234 | } 235 | 236 | /** 237 | * @return double the standard deviation. 238 | */ 239 | double computeStandardDeviation() const; 240 | 241 | private: 242 | double computeVariance() const; 243 | 244 | uint64_t count_ { 0 }; 245 | double mean_ { 0 }; 246 | double m2_ { 0 }; 247 | }; 248 | 249 | } // namespace Http 250 | } // namespace naf 251 | } // namespace efc 252 | -------------------------------------------------------------------------------- /http/source/http2/codec_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#include "../../../inc/EHttpSession.hh" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "../../include/codec.h" 12 | 13 | #include "../buffer_impl.h" 14 | #include "../linked_object.h" 15 | #include "../header_map_impl.h" 16 | 17 | #include "nghttp2/nghttp2.h" 18 | 19 | namespace efc { 20 | namespace naf { 21 | 22 | class EHttpSession; 23 | 24 | namespace Http { 25 | namespace Http2 { 26 | 27 | const std::string ALPN_STRING = "h2"; 28 | 29 | // This is not the full client magic, but it's the smallest size that should be able to 30 | // differentiate between HTTP/1 and HTTP/2. 31 | const std::string CLIENT_MAGIC_PREFIX = "PRI * HTTP/2"; 32 | 33 | class Utility { 34 | public: 35 | /** 36 | * Get the response status from the response headers. 37 | * @param headers supplies the headers to get the status from. 38 | * @return uint64_t the response code or throws an exception if the headers are invalid. 39 | */ 40 | static uint64_t getResponseStatus(const HeaderMap& headers); 41 | 42 | /** 43 | * Deal with https://tools.ietf.org/html/rfc7540#section-8.1.2.5 44 | * @param key supplies the incoming header key. 45 | * @param value supplies the incoming header value. 46 | * @param cookies supplies the header string to fill if this is a cookie header that needs to be 47 | * rebuilt. 48 | */ 49 | static bool reconstituteCrumbledCookies(const HeaderString& key, 50 | const HeaderString& value, HeaderString& cookies); 51 | }; 52 | 53 | /** 54 | * Base class for HTTP/2 client and server codecs. 55 | */ 56 | class ConnectionImpl: public virtual Connection { 57 | public: 58 | ConnectionImpl(sp& connection, /*Stats::Scope& stats,*/ 59 | const Http2Settings& http2_settings) : 60 | connection_(connection), per_stream_buffer_limit_( 61 | http2_settings.initial_stream_window_size_), dispatching_( 62 | false), raised_goaway_(false), pending_deferred_reset_( 63 | false) { 64 | } 65 | 66 | ~ConnectionImpl(); 67 | 68 | // Http::Connection 69 | void dispatch(sp& data) override; 70 | void goAway() override; 71 | Protocol protocol() override { 72 | return Protocol::Http2; 73 | } 74 | 75 | protected: 76 | /** 77 | * Wrapper for static nghttp2 callback dispatchers. 78 | */ 79 | class Http2Callbacks { 80 | public: 81 | Http2Callbacks(); 82 | ~Http2Callbacks(); 83 | 84 | const nghttp2_session_callbacks* callbacks() {return callbacks_;} 85 | 86 | private: 87 | nghttp2_session_callbacks* callbacks_; 88 | }; 89 | 90 | /** 91 | * Wrapper for static nghttp2 session options. 92 | */ 93 | class Http2Options { 94 | public: 95 | Http2Options(); 96 | ~Http2Options(); 97 | 98 | const nghttp2_option* options() {return options_;} 99 | 100 | private: 101 | nghttp2_option* options_; 102 | }; 103 | 104 | /** 105 | * Base class for client and server side streams. 106 | */ 107 | struct StreamImpl : public StreamEncoder, 108 | public Stream, 109 | public LinkedObject { 110 | StreamImpl(ConnectionImpl& parent, uint32_t buffer_limit); 111 | 112 | StreamImpl* base() {return this;} 113 | ssize_t onDataSourceRead(uint64_t length, uint32_t* data_flags); 114 | int onDataSourceSend(const uint8_t* framehd, size_t length); 115 | void resetStreamWorker(StreamResetReason reason); 116 | static void buildHeaders(std::vector& final_headers, const HeaderMap& headers); 117 | void saveHeader(HeaderString&& name, HeaderString&& value); 118 | virtual void submitHeaders(const std::vector& final_headers, 119 | nghttp2_data_provider* provider) = 0; 120 | void submitTrailers(const HeaderMap& trailers); 121 | 122 | // Http::StreamEncoder 123 | void encode100ContinueHeaders(const HeaderMap& headers) override; 124 | void encodeHeaders(const HeaderMap& headers, bool end_stream) override; 125 | void encodeData(Buffer::Instance& data, bool end_stream) override; 126 | void encodeTrailers(const HeaderMap& trailers) override; 127 | 128 | // Http::Stream 129 | void resetStream(StreamResetReason reason) override; 130 | 131 | // Max header size of 63K. This is arbitrary but makes it easier to test since nghttp2 doesn't 132 | // appear to transmit headers greater than approximtely 64K (NGHTTP2_MAX_HEADERSLEN) for reasons 133 | // I don't fully understand. 134 | static const uint64_t MAX_HEADER_SIZE = 63 * 1024; 135 | 136 | bool buffers_overrun() const {return read_disable_count_ > 0;} 137 | 138 | ConnectionImpl& parent_; 139 | HeaderMapImplPtr headers_; 140 | StreamDecoder* decoder_ {}; 141 | int32_t stream_id_ {-1}; 142 | uint32_t unconsumed_bytes_ {0}; 143 | uint32_t read_disable_count_ {0}; 144 | Buffer::OwnedImpl pending_recv_data_ {}; 145 | Buffer::OwnedImpl pending_send_data_ {}; 146 | 147 | HeaderMapPtr pending_trailers_; 148 | sp deferred_reset_; //cxxjava 149 | HeaderString cookies_; 150 | bool local_end_stream_sent_ : 1; 151 | bool remote_end_stream_ : 1; 152 | bool data_deferred_ : 1; 153 | bool waiting_for_non_informational_headers_ : 1; 154 | 155 | bool local_end_stream_ {}; //@see: codec_helper.h 156 | }; 157 | 158 | typedef std::unique_ptr StreamImplPtr; 159 | 160 | /** 161 | * Client side stream (request). 162 | */ 163 | struct ClientStreamImpl : public StreamImpl { 164 | using StreamImpl::StreamImpl; 165 | 166 | // StreamImpl 167 | void submitHeaders(const std::vector& final_headers, 168 | nghttp2_data_provider* provider) override; 169 | }; 170 | 171 | /** 172 | * Server side stream (response). 173 | */ 174 | struct ServerStreamImpl : public StreamImpl { 175 | using StreamImpl::StreamImpl; 176 | 177 | // StreamImpl 178 | void submitHeaders(const std::vector& final_headers, 179 | nghttp2_data_provider* provider) override; 180 | }; 181 | 182 | ConnectionImpl* base() {return this;} 183 | StreamImpl* getStream(int32_t stream_id); 184 | int saveHeader(const nghttp2_frame* frame, HeaderString&& name, HeaderString&& value); 185 | void sendPendingFrames(); 186 | void sendSettings(const Http2Settings& http2_settings, bool disable_push); 187 | 188 | static Http2Callbacks http2_callbacks_; 189 | static Http2Options http2_options_; 190 | 191 | std::list active_streams_; 192 | nghttp2_session* session_ {}; 193 | sp connection_; 194 | uint32_t per_stream_buffer_limit_; 195 | 196 | private: 197 | virtual ConnectionCallbacks& callbacks() = 0; 198 | virtual int onBeginHeaders(const nghttp2_frame* frame) = 0; 199 | int onData(int32_t stream_id, const uint8_t* data, size_t len); 200 | int onFrameReceived(const nghttp2_frame* frame); 201 | int onFrameSend(const nghttp2_frame* frame); 202 | virtual int onHeader(const nghttp2_frame* frame, HeaderString&& name, HeaderString&& value) = 0; 203 | int onInvalidFrame(int error_code); 204 | ssize_t onSend(const uint8_t* data, size_t length); 205 | int onStreamClose(int32_t stream_id, uint32_t error_code); 206 | 207 | bool dispatching_ : 1; 208 | bool raised_goaway_ : 1; 209 | bool pending_deferred_reset_ : 1; 210 | }; 211 | 212 | /** 213 | * HTTP/2 server connection codec. 214 | */ 215 | class ServerConnectionImpl: public ServerConnection, public ConnectionImpl { 216 | public: 217 | ServerConnectionImpl(sp& connection, 218 | ServerConnectionCallbacks& callbacks, const Http2Settings& http2_settings); 219 | 220 | private: 221 | // ConnectionImpl 222 | ConnectionCallbacks& callbacks() override {return callbacks_;} 223 | int onBeginHeaders(const nghttp2_frame* frame) override; 224 | int onHeader(const nghttp2_frame* frame, HeaderString&& name, HeaderString&& value) override; 225 | 226 | ServerConnectionCallbacks& callbacks_; 227 | }; 228 | 229 | } // namespace Http2 230 | } // namespace Http 231 | } // namespace naf 232 | } // namespace efc 233 | -------------------------------------------------------------------------------- /inc/EIoServiceStatistics.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoServiceStatistics.hh 3 | * 4 | * Created on: 2017-4-15 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef EIOSERVICESTATISTICS_HH_ 9 | #define EIOSERVICESTATISTICS_HH_ 10 | 11 | #include "Efc.hh" 12 | 13 | namespace efc { 14 | namespace naf { 15 | 16 | class EIoService; 17 | 18 | /** 19 | * Provides usage statistics for an {@link EIoService} instance. 20 | * 21 | */ 22 | class EIoServiceStatistics : public EObject { 23 | public: 24 | EIoServiceStatistics(EIoService* service); 25 | 26 | /** 27 | * Returns the maximum number of sessions which were being managed at the 28 | * same time. 29 | */ 30 | int getLargestManagedSessionCount(); 31 | 32 | /** 33 | * Returns the cumulative number of sessions which were managed (or are 34 | * being managed) by this service, which means 'currently managed session 35 | * count + closed session count'. 36 | */ 37 | llong getCumulativeManagedSessionCount(); 38 | 39 | /** 40 | * Returns the time in millis when I/O occurred lastly. 41 | */ 42 | llong getLastIoTime(); 43 | 44 | /** 45 | * Returns the time in millis when read operation occurred lastly. 46 | */ 47 | llong getLastReadTime(); 48 | 49 | /** 50 | * Returns the time in millis when write operation occurred lastly. 51 | */ 52 | llong getLastWriteTime(); 53 | 54 | /** 55 | * Returns the number of bytes read by this service 56 | * 57 | * @return 58 | * The number of bytes this service has read 59 | */ 60 | llong getReadBytes(); 61 | 62 | /** 63 | * Returns the number of bytes written out by this service 64 | * 65 | * @return 66 | * The number of bytes this service has written 67 | */ 68 | llong getWrittenBytes(); 69 | 70 | /** 71 | * Returns the number of messages this services has read 72 | * 73 | * @return 74 | * The number of messages this services has read 75 | */ 76 | llong getReadMessages(); 77 | 78 | /** 79 | * Returns the number of messages this service has written 80 | * 81 | * @return 82 | * The number of messages this service has written 83 | */ 84 | llong getWrittenMessages(); 85 | 86 | /** 87 | * Returns the number of read bytes per second. 88 | */ 89 | double getReadBytesThroughput(); 90 | 91 | /** 92 | * Returns the number of written bytes per second. 93 | */ 94 | double getWrittenBytesThroughput(); 95 | 96 | /** 97 | * Returns the number of read messages per second. 98 | */ 99 | double getReadMessagesThroughput(); 100 | 101 | /** 102 | * Returns the number of written messages per second. 103 | */ 104 | double getWrittenMessagesThroughput(); 105 | 106 | /** 107 | * Returns the maximum of the {@link #getReadBytesThroughput() readBytesThroughput}. 108 | */ 109 | double getLargestReadBytesThroughput(); 110 | 111 | /** 112 | * Returns the maximum of the {@link #getWrittenBytesThroughput() writtenBytesThroughput}. 113 | */ 114 | double getLargestWrittenBytesThroughput(); 115 | 116 | /** 117 | * Returns the maximum of the {@link #getReadMessagesThroughput() readMessagesThroughput}. 118 | */ 119 | double getLargestReadMessagesThroughput(); 120 | 121 | /** 122 | * Returns the maximum of the {@link #getWrittenMessagesThroughput() writtenMessagesThroughput}. 123 | */ 124 | double getLargestWrittenMessagesThroughput(); 125 | 126 | /** 127 | * Returns the interval (seconds) between each throughput calculation. 128 | * The default value is 3 seconds. 129 | */ 130 | int getThroughputCalculationInterval(); 131 | 132 | /** 133 | * Sets the interval (seconds) between each throughput calculation. The 134 | * default value is 3 seconds. 135 | * 136 | * @param throughputCalculationInterval The interval between two calculation 137 | */ 138 | void setThroughputCalculationInterval(int throughputCalculationInterval); 139 | 140 | protected: 141 | friend class ESocketAcceptor; 142 | friend class EIoSession; 143 | 144 | EAtomicDouble readBytesThroughput; 145 | EAtomicDouble writtenBytesThroughput; 146 | EAtomicDouble readMessagesThroughput; 147 | EAtomicDouble writtenMessagesThroughput; 148 | EAtomicDouble largestReadBytesThroughput; 149 | EAtomicDouble largestWrittenBytesThroughput; 150 | EAtomicDouble largestReadMessagesThroughput; 151 | EAtomicDouble largestWrittenMessagesThroughput; 152 | 153 | EAtomicLLong readBytes; 154 | EAtomicLLong writtenBytes; 155 | EAtomicLLong readMessages; 156 | EAtomicLLong writtenMessages; 157 | EAtomicLLong lastReadTime; 158 | EAtomicLLong lastWriteTime; 159 | 160 | /** The time (in second) between the computation of the service's statistics */ 161 | EAtomicInteger throughputCalculationInterval;// = new AtomicInteger(3); 162 | 163 | /** A counter used to store the maximum sessions we managed since the listenerSupport has been activated */ 164 | EAtomicInteger largestManagedSessionCount;// = 0; 165 | 166 | /** A global counter to count the number of sessions managed since the start */ 167 | EAtomicLLong cumulativeManagedSessionCount;// = 0; 168 | 169 | /** 170 | * Increases the count of read bytes by increment and sets 171 | * the last read time to currentTime. 172 | */ 173 | void increaseReadBytes(long increment, llong currentTime); 174 | 175 | /** 176 | * Increases the count of read messages by 1 and sets the last read time to 177 | * currentTime. 178 | */ 179 | void increaseReadMessages(llong currentTime); 180 | 181 | /** 182 | * Increases the count of written bytes by increment and sets 183 | * the last write time to currentTime. 184 | */ 185 | void increaseWrittenBytes(int increment, llong currentTime); 186 | 187 | /** 188 | * Increases the count of written messages by 1 and sets the last write time to 189 | * currentTime. 190 | */ 191 | void increaseWrittenMessages(llong currentTime); 192 | 193 | /** 194 | * Updates the throughput counters. 195 | * 196 | * @param currentTime The current time 197 | */ 198 | void updateThroughput(llong currentTime); 199 | 200 | private: 201 | struct ThreadThroughput: public EObject { 202 | /** The number of bytes read per second */ 203 | EAtomicDouble readBytesThroughput; 204 | 205 | /** The number of bytes written per second */ 206 | EAtomicDouble writtenBytesThroughput; 207 | 208 | /** The number of messages read per second */ 209 | EAtomicDouble readMessagesThroughput; 210 | 211 | /** The number of messages written per second */ 212 | EAtomicDouble writtenMessagesThroughput; 213 | 214 | /** The biggest number of bytes read per second */ 215 | EAtomicDouble largestReadBytesThroughput; 216 | 217 | /** The biggest number of bytes written per second */ 218 | EAtomicDouble largestWrittenBytesThroughput; 219 | 220 | /** The biggest number of messages read per second */ 221 | EAtomicDouble largestReadMessagesThroughput; 222 | 223 | /** The biggest number of messages written per second */ 224 | EAtomicDouble largestWrittenMessagesThroughput; 225 | 226 | /** The number of read bytes since the service has been started */ 227 | EAtomicLLong readBytes; 228 | 229 | /** The number of written bytes since the service has been started */ 230 | EAtomicLLong writtenBytes; 231 | 232 | /** The number of read messages since the service has been started */ 233 | EAtomicLLong readMessages; 234 | 235 | /** The number of written messages since the service has been started */ 236 | EAtomicLLong writtenMessages; 237 | 238 | /** The time the last read operation occurred */ 239 | EAtomicLLong lastReadTime; 240 | 241 | /** The time the last write operation occurred */ 242 | EAtomicLLong lastWriteTime; 243 | }; 244 | 245 | EIoService* service; 246 | int workThreads; 247 | EA threadThroughput; 248 | 249 | llong lastThroughputCalculationTime; 250 | llong lastReadBytes; 251 | llong lastWrittenBytes; 252 | llong lastReadMessages; 253 | llong lastWrittenMessages; 254 | }; 255 | 256 | } /* namespace naf */ 257 | } /* namespace efc */ 258 | #endif /* EIOSERVICESTATISTICS_HH_ */ 259 | -------------------------------------------------------------------------------- /inc/EIoFilterChain.hh: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoFilterChain.hh 3 | * 4 | * Created on: 2017-3-16 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #ifndef NFILTERCHAIN_HH_ 9 | #define NFILTERCHAIN_HH_ 10 | 11 | #include "./EIoFilter.hh" 12 | 13 | namespace efc { 14 | namespace naf { 15 | 16 | /** 17 | * A default implementation of {@link IoFilterChain} that provides 18 | * all operations for developers who want to implement their own 19 | * transport layer once used with {@link EIoSession}. 20 | * 21 | */ 22 | 23 | class EIoFilterChain: public EObject { 24 | public: 25 | /** 26 | * Represents a name-filter pair that an {@link IoFilterChain} contains. 27 | * 28 | * @author Apache MINA Project 29 | */ 30 | interface Entry: virtual public EObject { 31 | /** 32 | * @return the name of the filter. 33 | */ 34 | virtual const char* getName() = 0; 35 | 36 | /** 37 | * @return the filter. 38 | */ 39 | virtual EIoFilter* getFilter() = 0; 40 | 41 | /** 42 | * @return The {@link NextFilter} of the filter. 43 | */ 44 | virtual EIoFilter::NextFilter* getNextFilter() = 0; 45 | 46 | /** 47 | * Adds the specified filter with the specified name just before this entry. 48 | * 49 | * @param name The Filter's name 50 | * @param filter The added Filter 51 | */ 52 | virtual void addBefore(const char* name, EIoFilter* filter) = 0; 53 | 54 | /** 55 | * Adds the specified filter with the specified name just after this entry. 56 | * 57 | * @param name The Filter's name 58 | * @param filter The added Filter 59 | */ 60 | virtual void addAfter(const char* name, EIoFilter* filter) = 0; 61 | 62 | /** 63 | * Removes this entry from the chain it belongs to. 64 | */ 65 | virtual void remove() = 0; 66 | }; 67 | 68 | public: 69 | virtual ~EIoFilterChain(); 70 | 71 | /** 72 | * Creates a new instance with an empty filter list. 73 | */ 74 | EIoFilterChain(EIoSession* session); 75 | 76 | /** 77 | * Get the associated session 78 | */ 79 | EIoSession* getSession(); 80 | 81 | /** 82 | * Returns the {@link Entry} with the specified name in this chain. 83 | * 84 | * @param name The filter's name we are looking for 85 | * @return null if there's no such name in this chain 86 | */ 87 | Entry* getEntry(const char* name); 88 | 89 | /** 90 | * @see IoFilterChain#getEntry(IoFilter) 91 | * 92 | * @param filter The Filter we are looking for 93 | * @return The found Entry 94 | */ 95 | Entry* getEntry(EIoFilter* filter); 96 | 97 | /** 98 | * @see IoFilterChain#get(String) 99 | * 100 | * @param name The Filter's name we are looking for 101 | * @return The found Filter, or null 102 | */ 103 | EIoFilter* get(const char* name); 104 | 105 | /** 106 | * @see IoFilterChain#contains(String) 107 | * 108 | * @param name The Filter's name we want to check if it's in the chain 109 | * @return true if the chain contains the given filter name 110 | */ 111 | boolean contains(const char* name); 112 | 113 | /** 114 | * @see IoFilterChain#contains(IoFilter) 115 | * 116 | * @param filter The Filter we want to check if it's in the chain 117 | * @return true if the chain contains the given filter 118 | */ 119 | boolean contains(EIoFilter* filter); 120 | 121 | /** 122 | * 123 | */ 124 | EIoFilter::NextFilter* getNextFilter(const char* name); 125 | EIoFilter::NextFilter* getNextFilter(EIoFilter* filter); 126 | 127 | /** 128 | * @see IoFilterChain#addFirst(String, IoFilter) 129 | * 130 | * @param name The filter's name 131 | * @param filter The filter to add 132 | */ 133 | void addFirst(const char* name, EIoFilter* filter); 134 | 135 | /** 136 | * @see IoFilterChain#addLast(String, IoFilter) 137 | * 138 | * @param name The filter's name 139 | * @param filter The filter to add 140 | */ 141 | void addLast(const char* name, EIoFilter* filter); 142 | 143 | /** 144 | * @see IoFilterChain#addBefore(String, String, IoFilter) 145 | * 146 | * @param baseName The filter baseName 147 | * @param name The filter's name 148 | * @param filter The filter to add 149 | */ 150 | void addBefore(const char* baseName, const char* name, EIoFilter* filter); 151 | 152 | /** 153 | * @see IoFilterChain#addAfter(String, String, IoFilter) 154 | * 155 | * @param baseName The filter baseName 156 | * @param name The filter's name 157 | * @param filter The filter to add 158 | */ 159 | void addAfter(const char* baseName, const char* name, EIoFilter* filter); 160 | 161 | /** 162 | * @see IoFilterChain#remove(String) 163 | * 164 | * @param name The Filter's name to remove from the list of Filters 165 | * @return The removed IoFilter 166 | */ 167 | EIoFilter* remove(const char* name); 168 | 169 | /** 170 | * @see IoFilterChain#remove(IoFilter) 171 | * 172 | * @param filter The Filter we want to remove from the list of Filters 173 | * @return The removed IoFilter 174 | */ 175 | EIoFilter* remove(EIoFilter* filter); 176 | 177 | /** 178 | * @see IoFilterChain#clear() 179 | */ 180 | void clear(); 181 | 182 | /** 183 | * Fires a {@link IoHandler#sessionCreated(IoSession)} event. Most users don't need to 184 | * call this method at all. Please use this method only when you implement a new transport 185 | * or fire a virtual event. 186 | */ 187 | virtual boolean fireSessionCreated(); 188 | 189 | /** 190 | * Fires a {@link IoHandler#sessionClosed(IoSession)} event. Most users don't need to call 191 | * this method at all. Please use this method only when you implement a new transport or 192 | * fire a virtual event. 193 | */ 194 | virtual void fireSessionClosed(); 195 | 196 | /** 197 | * Fires a {@link IoHandler#messageReceived(Object)} event. Most users don't need to 198 | * call this method at all. Please use this method only when you implement a new transport 199 | * or fire a virtual event. 200 | * 201 | * @param message The received message 202 | */ 203 | virtual sp fireMessageReceived(sp message); 204 | 205 | /** 206 | * Fires a {@link IoHandler#messageSend(IoSession)} event. Most users don't need to call 207 | * this method at all. Please use this method only when you implement a new transport or 208 | * fire a virtual event. 209 | * 210 | * @param request The sent request 211 | */ 212 | virtual sp fireMessageSend(sp message); 213 | 214 | /** 215 | * 216 | */ 217 | virtual EString toString(); 218 | 219 | private: 220 | class EntryImpl; 221 | 222 | /** The associated session */ 223 | EIoSession* session; 224 | 225 | /** The mapping between the filters and their associated name */ 226 | //cxxjava: name2entry use HashMap at mina-2.0.0-RC1 and use ConcurrentHashMap at later versions. 227 | EMap* name2entry; 228 | 229 | /** The chain head */ 230 | EntryImpl* head; 231 | 232 | /** The chain tail */ 233 | EntryImpl* tail; 234 | 235 | /** 236 | * Checks the specified filter name is already taken and throws an exception if already taken. 237 | */ 238 | void checkAddable(const char* name); 239 | 240 | /** 241 | * Register the newly added filter, inserting it between the previous and 242 | * the next filter in the filter's chain. We also call the preAdd and 243 | * postAdd methods. 244 | */ 245 | void register_(EntryImpl* prevEntry, const char* name, EIoFilter* filter); 246 | 247 | void deregister(EntryImpl* entry); 248 | 249 | /** 250 | * Throws an exception when the specified filter name is not registered in this chain. 251 | * 252 | * @return An filter entry with the specified name. 253 | */ 254 | EntryImpl* checkOldName(const char* baseName); 255 | 256 | boolean callNextSessionCreated(Entry* entry, EIoSession* session); 257 | void callNextSessionClosed(Entry* entry, EIoSession* session); 258 | sp callNextMessageReceived(Entry* entry, EIoSession* session, sp message); 259 | sp callNextMessageSend(Entry* entry, EIoSession* session, sp message); 260 | }; 261 | 262 | } /* namespace naf */ 263 | } /* namespace efc */ 264 | #endif /* NFILTERCHAIN_HH_ */ 265 | -------------------------------------------------------------------------------- /src/EIoServiceStatistics.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * EIoServiceStatistics.cpp 3 | * 4 | * Created on: 2014-9-15 5 | * Author: cxxjava@163.com 6 | */ 7 | 8 | #include "../inc/EIoServiceStatistics.hh" 9 | #include "../inc/EIoService.hh" 10 | #include "Eco.hh" 11 | 12 | namespace efc { 13 | namespace naf { 14 | 15 | EIoServiceStatistics::EIoServiceStatistics(EIoService* service) : 16 | service(service), 17 | workThreads(service->getWorkThreads()), 18 | threadThroughput(workThreads), 19 | throughputCalculationInterval(3), 20 | lastThroughputCalculationTime(0L), 21 | lastReadBytes(0L), 22 | lastWrittenBytes(0L), 23 | lastReadMessages(0L), 24 | lastWrittenMessages(0L) { 25 | for (int i=0; ithroughputCalculationInterval.set(throughputCalculationInterval); 111 | } 112 | 113 | void EIoServiceStatistics::updateThroughput(llong currentTime) { 114 | // readBytes, writtenBytes, readMessages, writtenMessages, lastReadTime, lastWriteTime 115 | llong readBytes, writtenBytes, readMessages, writtenMessages; 116 | llong lastReadTime0, lastReadTime; 117 | llong lastWriteTime0, lastWriteTime; 118 | readBytes = writtenBytes = readMessages = writtenMessages = 0L; 119 | lastReadTime0 = lastReadTime = this->lastReadTime.get(); 120 | lastWriteTime0 = lastWriteTime = this->lastWriteTime.get(); 121 | for (int i=0; ireadBytes.get(); 126 | writtenBytes += tt->writtenBytes.get(); 127 | readMessages += tt->readMessages.get(); 128 | writtenMessages += tt->writtenMessages.get(); 129 | 130 | t = tt->lastReadTime.get(); 131 | if (t > lastReadTime) { 132 | lastReadTime = t; 133 | } 134 | 135 | t = tt->lastWriteTime.get(); 136 | if (t > lastWriteTime) { 137 | lastWriteTime = t; 138 | } 139 | } 140 | this->readBytes.set(readBytes); 141 | this->writtenBytes.set(writtenBytes); 142 | this->readMessages.set(readMessages); 143 | this->writtenMessages.set(writtenMessages); 144 | if (lastReadTime > lastReadTime0) { 145 | this->lastReadTime.set(lastReadTime); 146 | } 147 | if (lastWriteTime > lastWriteTime0) { 148 | this->lastWriteTime.set(lastWriteTime); 149 | } 150 | 151 | // throughput calculate 152 | int interval = (int) (currentTime - lastThroughputCalculationTime); 153 | 154 | double rbt = (readBytes - lastReadBytes) * 1000.0 / interval; 155 | readBytesThroughput.set(rbt); 156 | double wbt = (writtenBytes - lastWrittenBytes) * 1000.0 / interval; 157 | writtenBytesThroughput.set(wbt); 158 | double rmt = (readMessages - lastReadMessages) * 1000.0 / interval; 159 | readMessagesThroughput.set(rmt); 160 | double wmt = (writtenMessages - lastWrittenMessages) * 1000.0 / interval; 161 | writtenMessagesThroughput.set(wmt); 162 | 163 | if (rbt > largestReadBytesThroughput.get()) { 164 | largestReadBytesThroughput.set(rbt); 165 | } 166 | 167 | if (wbt > largestWrittenBytesThroughput.get()) { 168 | largestWrittenBytesThroughput.set(wbt); 169 | } 170 | 171 | if (rmt > largestReadMessagesThroughput.get()) { 172 | largestReadMessagesThroughput.set(rmt); 173 | } 174 | 175 | if (wmt > largestWrittenMessagesThroughput.get()) { 176 | largestWrittenMessagesThroughput.set(wmt); 177 | } 178 | 179 | lastReadBytes = readBytes; 180 | lastWrittenBytes = writtenBytes; 181 | lastReadMessages = readMessages; 182 | lastWrittenMessages = writtenMessages; 183 | 184 | lastThroughputCalculationTime = currentTime; 185 | } 186 | 187 | void EIoServiceStatistics::increaseReadBytes(long increment, llong currentTime) { 188 | EFiber* fiber = EFiber::currentFiber(); 189 | if (!fiber) { 190 | throw ENullPointerException(__FILE__, __LINE__, "Out of fiber schedule."); 191 | } 192 | ThreadThroughput* tt = threadThroughput[fiber->getThreadIndex()]; 193 | tt->readBytes.addAndGet(increment); 194 | tt->lastReadTime.set(currentTime); 195 | } 196 | 197 | void EIoServiceStatistics::increaseReadMessages(llong currentTime) { 198 | EFiber* fiber = EFiber::currentFiber(); 199 | if (!fiber) { 200 | throw ENullPointerException(__FILE__, __LINE__, "Out of fiber schedule."); 201 | } 202 | ThreadThroughput* tt = threadThroughput[fiber->getThreadIndex()]; 203 | tt->readMessages.addAndGet(1); 204 | tt->lastReadTime.set(currentTime); 205 | } 206 | 207 | void EIoServiceStatistics::increaseWrittenBytes(int increment, llong currentTime) { 208 | EFiber* fiber = EFiber::currentFiber(); 209 | if (!fiber) { 210 | throw ENullPointerException(__FILE__, __LINE__, "Out of fiber schedule."); 211 | } 212 | ThreadThroughput* tt = threadThroughput[fiber->getThreadIndex()]; 213 | tt->writtenBytes.addAndGet(increment); 214 | tt->lastWriteTime.set(currentTime); 215 | } 216 | 217 | void EIoServiceStatistics::increaseWrittenMessages(llong currentTime) { 218 | EFiber* fiber = EFiber::currentFiber(); 219 | if (!fiber) { 220 | throw ENullPointerException(__FILE__, __LINE__, "Out of fiber schedule."); 221 | } 222 | ThreadThroughput* tt = threadThroughput[fiber->getThreadIndex()]; 223 | tt->writtenMessages.addAndGet(1); 224 | tt->lastWriteTime.set(currentTime); 225 | } 226 | // 227 | //void EIoServiceStatistics::setLastReadTime(llong lastReadTime) { 228 | // SYNCBLOCK(&throughputCalculationLock) { 229 | // this->lastReadTime = lastReadTime; 230 | // }} 231 | //} 232 | // 233 | //void EIoServiceStatistics::setLastWriteTime(llong lastWriteTime) { 234 | // SYNCBLOCK(&throughputCalculationLock) { 235 | // this->lastWriteTime = lastWriteTime; 236 | // }} 237 | //} 238 | // 239 | //void EIoServiceStatistics::setLastThroughputCalculationTime( 240 | // llong lastThroughputCalculationTime) { 241 | // SYNCBLOCK(&throughputCalculationLock) { 242 | // this->lastThroughputCalculationTime = lastThroughputCalculationTime; 243 | // }} 244 | //} 245 | 246 | } /* namespace naf */ 247 | } /* namespace efc */ 248 | -------------------------------------------------------------------------------- /http/source/http1/codec_impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "http_parser/http_parser.h" 4 | 5 | //#include "../../../inc/EHttpSession.hh" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "../../include/codec.h" 14 | 15 | #include "../buffer_impl.h" 16 | #include "../to_lower_table.h" 17 | #include "../codes.h" 18 | #include "../header_map_impl.h" 19 | 20 | namespace efc { 21 | namespace naf { 22 | 23 | class EHttpSession; 24 | 25 | namespace Http { 26 | namespace Http1 { 27 | 28 | class Utility { 29 | public: 30 | /** 31 | * Get the response status from the response headers. 32 | * @param headers supplies the headers to get the status from. 33 | * @return uint64_t the response code or throws an exception if the headers are invalid. 34 | */ 35 | static uint64_t getResponseStatus(const HeaderMap& headers); 36 | }; 37 | 38 | class ConnectionImpl; 39 | 40 | /** 41 | * Base class for HTTP/1.1 request and response encoders. 42 | */ 43 | class StreamEncoderImpl: public StreamEncoder, public Stream/*, 44 | public StreamCallbackHelper*/{ 45 | public: 46 | // Http::StreamEncoder 47 | void encode100ContinueHeaders(const HeaderMap& headers) override; 48 | void encodeHeaders(const HeaderMap& headers, bool end_stream) override; 49 | void encodeData(Buffer::Instance& data, bool end_stream) override; 50 | void encodeTrailers(const HeaderMap& trailers) override; 51 | 52 | void resetStream(StreamResetReason reason) override; 53 | 54 | protected: 55 | StreamEncoderImpl(ConnectionImpl& connection) : connection_(connection) {} 56 | 57 | static const std::string CRLF; 58 | static const std::string LAST_CHUNK; 59 | 60 | ConnectionImpl& connection_; 61 | 62 | private: 63 | /** 64 | * Called to encode an individual header. 65 | * @param key supplies the header to encode. 66 | * @param key_size supplies the byte size of the key. 67 | * @param value supplies the value to encode. 68 | * @param value_size supplies the byte size of the value. 69 | */ 70 | void encodeHeader(const char* key, uint32_t key_size, const char* value, uint32_t value_size); 71 | 72 | /** 73 | * Called to finalize a stream encode. 74 | */ 75 | void endEncode(); 76 | 77 | bool chunk_encoding_ {true}; 78 | bool processing_100_continue_ {false}; 79 | }; 80 | 81 | /** 82 | * HTTP/1.1 response encoder. 83 | */ 84 | class ResponseStreamEncoderImpl: public StreamEncoderImpl { 85 | public: 86 | ResponseStreamEncoderImpl(ConnectionImpl& connection) : 87 | StreamEncoderImpl(connection) { 88 | } 89 | 90 | bool startedResponse() { 91 | return started_response_; 92 | } 93 | 94 | // Http::StreamEncoder 95 | void encodeHeaders(const HeaderMap& headers, bool end_stream) override; 96 | 97 | private: 98 | bool started_response_ {}; 99 | }; 100 | 101 | /** 102 | * HTTP/1.1 request encoder. 103 | */ 104 | class RequestStreamEncoderImpl: public StreamEncoderImpl { 105 | public: 106 | RequestStreamEncoderImpl(ConnectionImpl& connection) : 107 | StreamEncoderImpl(connection) { 108 | } 109 | 110 | bool headRequest() { 111 | return head_request_; 112 | } 113 | 114 | // Http::StreamEncoder 115 | void encodeHeaders(const HeaderMap& headers, bool end_stream) override; 116 | 117 | private: 118 | bool head_request_ {}; 119 | }; 120 | 121 | /** 122 | * Base class for HTTP/1.1 client and server connections. 123 | */ 124 | class ConnectionImpl: public virtual Connection { 125 | public: 126 | /** 127 | * @return ESocketSession& the backing network connection. 128 | */ 129 | sp connection() { 130 | return connection_; 131 | } 132 | 133 | /** 134 | * Called when the active encoder has completed encoding the outbound half of the stream. 135 | */ 136 | virtual void onEncodeComplete() = 0; 137 | 138 | /** 139 | * Called when resetStream() has been called on an active stream. In HTTP/1.1 the only 140 | * valid operation after this point is for the connection to get blown away, but we will not 141 | * fire any more callbacks in case some stack has to unwind. 142 | */ 143 | void onResetStreamBase(StreamResetReason reason); 144 | 145 | /** 146 | * Flush all pending output from encoding. 147 | */ 148 | void flushOutput(); 149 | 150 | void addCharToBuffer(char c); 151 | void addIntToBuffer(uint64_t i); 152 | 153 | Buffer::OwnedImpl& buffer() { 154 | return output_buffer_; 155 | } 156 | 157 | void copyToBuffer(const char* data, uint64_t length); 158 | 159 | // Http::Connection 160 | void dispatch(sp& data) override; 161 | void goAway() override {} // Called during connection manager drain flow 162 | Protocol protocol() override {return protocol_;} 163 | 164 | virtual bool supports_http_10() {return false;} 165 | 166 | protected: 167 | ConnectionImpl(sp& connection, http_parser_type type); 168 | 169 | bool resetStreamCalled() {return reset_stream_called_;} 170 | 171 | sp connection_; 172 | http_parser parser_; 173 | HeaderMapPtr deferred_end_stream_headers_; 174 | Http::Code error_code_ {Http::Code::BadRequest}; 175 | 176 | private: 177 | enum class HeaderParsingState {Field, Value, Done}; 178 | 179 | /** 180 | * Called in order to complete an in progress header decode. 181 | */ 182 | void completeLastHeader(); 183 | 184 | /** 185 | * Dispatch a memory span. 186 | * @param slice supplies the start address. 187 | * @len supplies the lenght of the span. 188 | */ 189 | size_t dispatchSlice(const char* slice, size_t len); 190 | 191 | /** 192 | * Called when a request/response is beginning. A base routine happens first then a virtual 193 | * dispatch is invoked. 194 | */ 195 | void onMessageBeginBase(); 196 | virtual void onMessageBegin() = 0; 197 | 198 | /** 199 | * Called when URL data is received. 200 | * @param data supplies the start address. 201 | * @param lenth supplies the length. 202 | */ 203 | virtual void onUrl(const char* data, size_t length) = 0; 204 | 205 | /** 206 | * Called when header field data is received. 207 | * @param data supplies the start address. 208 | * @param length supplies the length. 209 | */ 210 | void onHeaderField(const char* data, size_t length); 211 | 212 | /** 213 | * Called when header value data is received. 214 | * @param data supplies the start address. 215 | * @param length supplies the length. 216 | */ 217 | void onHeaderValue(const char* data, size_t length); 218 | 219 | /** 220 | * Called when headers are complete. A base routine happens first then a virtual disaptch is 221 | * invoked. 222 | * @return 0 if no error, 1 if there should be no body. 223 | */ 224 | int onHeadersCompleteBase(); 225 | virtual int onHeadersComplete(HeaderMapImplPtr&& headers) = 0; 226 | 227 | /** 228 | * Called when body data is received. 229 | * @param data supplies the start address. 230 | * @param length supplies the length. 231 | */ 232 | virtual void onBody(const char* data, size_t length) = 0; 233 | 234 | /** 235 | * Called when the request/response is complete. 236 | */ 237 | virtual void onMessageComplete() = 0; 238 | 239 | /** 240 | * @see onResetStreamBase(). 241 | */ 242 | virtual void onResetStream(StreamResetReason reason) = 0; 243 | 244 | /** 245 | * Send a protocol error response to remote. 246 | */ 247 | virtual void sendProtocolError() = 0; 248 | 249 | static http_parser_settings settings_; 250 | static const ToLowerTable& toLowerTable(); 251 | 252 | HeaderMapImplPtr current_header_map_; 253 | HeaderParsingState header_parsing_state_ {HeaderParsingState::Field}; 254 | HeaderString current_header_field_; 255 | HeaderString current_header_value_; 256 | bool reset_stream_called_ {}; 257 | 258 | Buffer::OwnedImpl output_buffer_; 259 | 260 | sp reserved_iovec_; 261 | Protocol protocol_ {Protocol::Http11}; 262 | }; 263 | 264 | /** 265 | * Implementation of Http::ServerConnection for HTTP/1.1. 266 | */ 267 | class ServerConnectionImpl: public ServerConnection, public ConnectionImpl { 268 | public: 269 | ServerConnectionImpl(sp& connection, 270 | ServerConnectionCallbacks& callbacks, Http1Settings settings); 271 | 272 | virtual bool supports_http_10() override {return codec_settings_.accept_http_10_;} 273 | 274 | private: 275 | /** 276 | * An active HTTP/1.1 request. 277 | */ 278 | struct ActiveRequest { 279 | ActiveRequest(ConnectionImpl& connection) : 280 | response_encoder_(connection) { 281 | } 282 | 283 | HeaderString request_url_; 284 | StreamDecoder* request_decoder_ { }; 285 | ResponseStreamEncoderImpl response_encoder_;bool remote_complete_ { }; 286 | }; 287 | 288 | /** 289 | * Manipulate the request's first line, parsing the url and converting to a relative path if 290 | * neccessary. Compute Host / :authority headers based on 7230#5.7 and 7230#6 291 | * 292 | * @param is_connect true if the request has the CONNECT method 293 | * @param headers the request's headers 294 | * @throws CodecProtocolException on an invalid url in the request line 295 | */ 296 | void handlePath(HeaderMapImpl& headers, unsigned int method); 297 | 298 | // ConnectionImpl 299 | void onEncodeComplete() override; 300 | void onMessageBegin() override; 301 | void onUrl(const char* data, size_t length) override; 302 | int onHeadersComplete(HeaderMapImplPtr&& headers) override; 303 | void onBody(const char* data, size_t length) override; 304 | void onMessageComplete() override; 305 | void onResetStream(StreamResetReason reason) override; 306 | void sendProtocolError() override; 307 | 308 | ServerConnectionCallbacks& callbacks_; 309 | std::unique_ptr active_request_; 310 | Http1Settings codec_settings_; 311 | }; 312 | 313 | } // namespace http1 314 | } // namespace http 315 | } // namespace naf 316 | } // namespace efc 317 | --------------------------------------------------------------------------------