diff --git a/code/Base64/Base64.cpp b/code/Base64/Base64.cpp new file mode 100644 index 00000000..843719ec --- /dev/null +++ b/code/Base64/Base64.cpp @@ -0,0 +1,282 @@ +/* + base64.cpp and base64.h + + base64 encoding and decoding with C++. + More information at + https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp + + Version: 2.rc.09 (release candidate) + + Copyright (C) 2004-2017, 2020-2022 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ + +#include "base64.h" + +#include +#include + + // + // Depending on the url parameter in base64_chars, one of + // two sets of base64 characters needs to be chosen. + // They differ in their last two characters. + // +static const char* base64_chars[2] = { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "+/", + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "-_"}; + +static unsigned int pos_of_char(const unsigned char chr) { + // + // Return the position of chr within base64_encode() + // + + if (chr >= 'A' && chr <= 'Z') return chr - 'A'; + else if (chr >= 'a' && chr <= 'z') return chr - 'a' + ('Z' - 'A') + 1; + else if (chr >= '0' && chr <= '9') return chr - '0' + ('Z' - 'A') + ('z' - 'a') + 2; + else if (chr == '+' || chr == '-') return 62; // Be liberal with input and accept both url ('-') and non-url ('+') base 64 characters ( + else if (chr == '/' || chr == '_') return 63; // Ditto for '/' and '_' + else + // + // 2020-10-23: Throw std::exception rather than const char* + //(Pablo Martin-Gomez, https://github.com/Bouska) + // + throw std::runtime_error("Input is not valid base64-encoded data."); +} + +static std::string insert_linebreaks(std::string str, size_t distance) { + // + // Provided by https://github.com/JomaCorpFX, adapted by me. + // + if (!str.length()) { + return ""; + } + + size_t pos = distance; + + while (pos < str.size()) { + str.insert(pos, "\n"); + pos += distance + 1; + } + + return str; +} + +template +static std::string encode_with_line_breaks(String s) { + return insert_linebreaks(base64_encode(s, false), line_length); +} + +template +static std::string encode_pem(String s) { + return encode_with_line_breaks(s); +} + +template +static std::string encode_mime(String s) { + return encode_with_line_breaks(s); +} + +template +static std::string encode(String s, bool url) { + return base64_encode(reinterpret_cast(s.data()), s.length(), url); +} + +std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) { + + size_t len_encoded = (in_len +2) / 3 * 4; + + unsigned char trailing_char = url ? '.' : '='; + + // + // Choose set of base64 characters. They differ + // for the last two positions, depending on the url + // parameter. + // A bool (as is the parameter url) is guaranteed + // to evaluate to either 0 or 1 in C++ therefore, + // the correct character set is chosen by subscripting + // base64_chars with url. + // + const char* base64_chars_ = base64_chars[url]; + + std::string ret; + ret.reserve(len_encoded); + + unsigned int pos = 0; + + while (pos < in_len) { + ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]); + + if (pos+1 < in_len) { + ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]); + + if (pos+2 < in_len) { + ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]); + ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]); + } + else { + ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]); + ret.push_back(trailing_char); + } + } + else { + + ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]); + ret.push_back(trailing_char); + ret.push_back(trailing_char); + } + + pos += 3; + } + + + return ret; +} + +template +static std::string decode(String const& encoded_string, bool remove_linebreaks) { + // + // decode(…) is templated so that it can be used with String = const std::string& + // or std::string_view (requires at least C++17) + // + + if (encoded_string.empty()) return std::string(); + + if (remove_linebreaks) { + + std::string copy(encoded_string); + + copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end()); + + return base64_decode(copy, false); + } + + size_t length_of_string = encoded_string.length(); + size_t pos = 0; + + // + // The approximate length (bytes) of the decoded string might be one or + // two bytes smaller, depending on the amount of trailing equal signs + // in the encoded string. This approximation is needed to reserve + // enough space in the string to be returned. + // + size_t approx_length_of_decoded_string = length_of_string / 4 * 3; + std::string ret; + ret.reserve(approx_length_of_decoded_string); + + while (pos < length_of_string) { + // + // Iterate over encoded input string in chunks. The size of all + // chunks except the last one is 4 bytes. + // + // The last chunk might be padded with equal signs or dots + // in order to make it 4 bytes in size as well, but this + // is not required as per RFC 2045. + // + // All chunks except the last one produce three output bytes. + // + // The last chunk produces at least one and up to three bytes. + // + + size_t pos_of_char_1 = pos_of_char(encoded_string.at(pos+1) ); + + // + // Emit the first output byte that is produced in each chunk: + // + ret.push_back(static_cast( ( (pos_of_char(encoded_string.at(pos+0)) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4))); + + if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045) + encoded_string.at(pos+2) != '=' && + encoded_string.at(pos+2) != '.' // accept URL-safe base 64 strings, too, so check for '.' also. + ) + { + // + // Emit a chunk's second byte (which might not be produced in the last chunk). + // + unsigned int pos_of_char_2 = pos_of_char(encoded_string.at(pos+2) ); + ret.push_back(static_cast( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2))); + + if ( ( pos + 3 < length_of_string ) && + encoded_string.at(pos+3) != '=' && + encoded_string.at(pos+3) != '.' + ) + { + // + // Emit a chunk's third byte (which might not be produced in the last chunk). + // + ret.push_back(static_cast( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string.at(pos+3)) )); + } + } + + pos += 4; + } + + return ret; +} + +std::string base64_decode(std::string const& s, bool remove_linebreaks) { + return decode(s, remove_linebreaks); +} + +std::string base64_encode(std::string const& s, bool url) { + return encode(s, url); +} + +std::string base64_encode_pem (std::string const& s) { + return encode_pem(s); +} + +std::string base64_encode_mime(std::string const& s) { + return encode_mime(s); +} + +#if __cplusplus >= 201703L +// +// Interface with std::string_view rather than const std::string& +// Requires C++17 +// Provided by Yannic Bonenberger (https://github.com/Yannic) +// + +std::string base64_encode(std::string_view s, bool url) { + return encode(s, url); +} + +std::string base64_encode_pem(std::string_view s) { + return encode_pem(s); +} + +std::string base64_encode_mime(std::string_view s) { + return encode_mime(s); +} + +std::string base64_decode(std::string_view s, bool remove_linebreaks) { + return decode(s, remove_linebreaks); +} + +#endif // __cplusplus >= 201703L diff --git a/code/Base64/Base64.h b/code/Base64/Base64.h new file mode 100644 index 00000000..4860d63d --- /dev/null +++ b/code/Base64/Base64.h @@ -0,0 +1,35 @@ +// +// base64 encoding and decoding with C++. +// Version: 2.rc.09 (release candidate) +// + +#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A +#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A + +#include + +#if __cplusplus >= 201703L +#include +#endif // __cplusplus >= 201703L + +std::string base64_encode (std::string const& s, bool url = false); +std::string base64_encode_pem (std::string const& s); +std::string base64_encode_mime(std::string const& s); + +std::string base64_decode(std::string const& s, bool remove_linebreaks = false); +std::string base64_encode(unsigned char const*, size_t len, bool url = false); + +#if __cplusplus >= 201703L +// +// Interface with std::string_view rather than const std::string& +// Requires C++17 +// Provided by Yannic Bonenberger (https://github.com/Yannic) +// +std::string base64_encode (std::string_view s, bool url = false); +std::string base64_encode_pem (std::string_view s); +std::string base64_encode_mime(std::string_view s); + +std::string base64_decode(std::string_view s, bool remove_linebreaks = false); +#endif // __cplusplus >= 201703L + +#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */ diff --git a/code/MD5/MD5.cpp b/code/MD5/MD5.cpp new file mode 100644 index 00000000..889e279d --- /dev/null +++ b/code/MD5/MD5.cpp @@ -0,0 +1,112 @@ +#include "MD5.h" + + MD5::MD5() { + tempA = A; + tempB = B; + tempC = C; + tempD = D; + strlength = 0; + } + // F函数 + unsigned int MD5::F(unsigned int b, unsigned int c, unsigned int d) { + return (b & c) | ((~b) & d); + } + // G函数 + unsigned int MD5::G(unsigned int b, unsigned int c, unsigned int d) { + return (b & d) | (c & (~d)); + } + // H函数 + unsigned int MD5::H(unsigned int b, unsigned int c, unsigned int d) { + return b ^ c ^ d; + } + // I函数 + unsigned int MD5::I(unsigned int b, unsigned int c, unsigned int d) { + return c ^ (b | (~d)); + } + // 移位操作函数 + unsigned int MD5::shift(unsigned int a, unsigned int n) { + return (a << n) | (a >> (32 - n)); + } + // 编码函数 + std::string MD5::encode(std::string src) { + std::vector rec = padding(src); + for(unsigned int i = 0; i < strlength/16; i++) { + unsigned int num[16]; + for(int j = 0; j < 16; j++) { + num[j] = rec[i*16+j]; + } + iterateFunc(num, 16); + } + return format(tempA) + format(tempB) + format(tempC) + format(tempD); + } + // 循环压缩 + void MD5::iterateFunc(unsigned int* X, int size = 16) { + unsigned int a = tempA, + b = tempB, + c = tempC, + d = tempD, + rec = 0, + g, k; + for(int i = 0; i < 64; i++) { + if(i < 16) { + // F迭代 + g = F(b, c, d); + k = i; + } + else if(i < 32) { + // G迭代 + g = G(b, c, d); + k = (1 + 5*i) % 16; + } + else if(i < 48) { + // H迭代 + g = H(b, c, d); + k = (5 + 3*i) % 16; + } + else { + // I迭代 + g = I(b, c, d); + k = (7*i) % 16; + } + rec = d; + d = c; + c = b; + b = b + shift(a + g + X[k] + T[i], s[i]); + a = rec; + } + tempA += a; + tempB += b; + tempC += c; + tempD += d; + } + // 填充字符串 + std::vector MD5::padding(std::string src) { + // 以512位,64个字节为一组 + unsigned int num = ((src.length() + 8) / 64) + 1; + std::vector rec(num*16); + strlength = num*16; + for(unsigned int i = 0; i < src.length(); i++){ + // 一个unsigned int对应4个字节,保存4个字符信息 + rec[i>>2] |= (int)(src[i]) << ((i % 4) * 8); + } + // 补充1000...000 + rec[src.length() >> 2] |= (0x80 << ((src.length() % 4)*8)); + // 填充原文长度 + rec[rec.size()-2] = (src.length() << 3); + return rec; + } + // 整理输出 + std::string MD5::format(unsigned int num) { + std::string res = ""; + unsigned int base = 1 << 8; + for(int i = 0; i < 4; i++) { + std::string tmp = ""; + unsigned int b = (num >> (i * 8)) % base & 0xff; + for(int j = 0; j < 2; j++) { + tmp = str16[b%16] + tmp; + b /= 16; + } + res += tmp; + } + return res; + } diff --git a/code/MD5/MD5.h b/code/MD5/MD5.h new file mode 100644 index 00000000..1cb85e33 --- /dev/null +++ b/code/MD5/MD5.h @@ -0,0 +1,54 @@ +#ifndef __MD5__H__ +#define __MD5__H__ + +#include +#include +#include +#include + +#define A 0x67452301 +#define B 0xefcdab89 +#define C 0x98badcfe +#define D 0x10325476 + +const char str16[] = "0123456789abcdef"; + +const unsigned int T[] = { + 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee, + 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501, + 0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be, + 0x6b901122,0xfd987193,0xa679438e,0x49b40821, + 0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa, + 0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, + 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed, + 0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a, + 0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c, + 0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70, + 0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05, + 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665, + 0xf4292244,0x432aff97,0xab9423a7,0xfc93a039, + 0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1, + 0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1, + 0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391 }; + +const unsigned int s[] = { 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22, + 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, + 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23, + 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21}; +class MD5 { + private: + unsigned int tempA, tempB, tempC, tempD, strlength; + public: + MD5(); + unsigned int F(unsigned int b, unsigned int c, unsigned int d); + unsigned int G(unsigned int b, unsigned int c, unsigned int d); + unsigned int H(unsigned int b, unsigned int c, unsigned int d); + unsigned int I(unsigned int b, unsigned int c, unsigned int d); + unsigned int shift(unsigned int a, unsigned int n); + std::string encode(std::string src); + void iterateFunc(unsigned int* X, int size); + std::vector padding(std::string src); + std::string format(unsigned int num); + }; + +#endif diff --git a/code/http/HttpDeal.h b/code/http/HttpDeal.h new file mode 100644 index 00000000..1edd7719 --- /dev/null +++ b/code/http/HttpDeal.h @@ -0,0 +1,74 @@ +#ifndef HTTP_DEAL_H +#define HTTP_DEAL_H +#include +#include +#include +#include +#include "../MD5/MD5.h" +#include "../webserver/DEBUGUTIL.h" +#include "HttpUtil.h" +#include "../buffer/buffer.h" +#include "../mysql/sqlconnpool.h" +#include "../mysql/mysqlUtil.h" +typedef enum{ + NONE,GET,POST,DELETE,PUT, +} HTTP_ENUM_E; +typedef struct{ + HTTP_ENUM_E enumMethod = NONE; + std::string strPath; + std::string strVersion; + bool isKeepAlive = false; + ssize_t iHeaderLen = 0; + ssize_t iContentLen = 0; + std::unordered_map mapHeader; +} HTTP_HEADER_T; +typedef struct{ + HTTP_ENUM_E enumMethod; + std::string strUrl; + std::function funCallBack; + +} HTTP_REQUEST_T; + +typedef struct +{ + std::string strRealm; + std::string strUser; + std::string strUri; + std::string strCnonce; + std::string strNonce; + std::string strResponse; + std::string strQop = "auth"; + std::string strNc = "00000001"; + +} HTTP_DIGEST_AUTH_T; +class HttpDeal +{ +private: + Buffer* pWriteBuff_; + Buffer* pReadBuff_; + HTTP_HEADER_T struHttpHead_; + HTTP_DIGEST_AUTH_T struHttpDigest_; + /* data */ +public: + static std::unordered_map httpUrlMap; + static std::unordered_map mapReturnCode; + static std::unordered_map mapHttpMethod; + std::string genDigestAuthenticate(const std::string& realm,std::string& nonce); + std::string genHeadLine(const std::string& strKey,const std::string& strValue); + std::string genHeadFirstLine(int iCode); + int httpPraseAuthorization(std::string& strAuth,HTTP_DIGEST_AUTH_T& struDigest); + int getPage(); + int getHomePage(); + int PraseHttpHeader(); + int doDigestAuth(); + HttpDeal(/* args */); + ~HttpDeal(); + void init(Buffer* pReadBuff,Buffer* pWriteBuff); + bool IsKeepAlive() const; + void initHeaderStruct(); + int processHttp(); + int processCommonPage(); +}; + + +#endif diff --git a/code/http/httpDeal.cpp b/code/http/httpDeal.cpp new file mode 100644 index 00000000..da70811f --- /dev/null +++ b/code/http/httpDeal.cpp @@ -0,0 +1,355 @@ +#include "HttpDeal.h" +static const std::string HTTP_VERSON_HEAD = "HTTP/1.1 "; +static const std::string HTTP_SPLIE = "\r\n"; +static const std::string HTTP_HEAD_END = "\r\n\r\n"; +static const std::string CONTENT_LENGTH = "Content-Length"; +static const std::string Authenticate = "WWW-Authenticate"; +std::unordered_map HttpDeal::mapReturnCode = { + {200, "200 OK"}, + {401, "401 Unauthorized"}, + {404, "404 Not Found"}, + {405, "405 Not Allowed"}, +}; + +std::unordered_map HttpDeal::httpUrlMap; +std::vector vecHttpMethod = { + "GET", "POST", "DELETE", "PUT"}; +std::unordered_map HttpDeal::mapHttpMethod = { + {GET, "GET"}, + {POST, "POST"}, + {DELETE, "DELETE"}, + {PUT, "PUT"}, +}; + +std::string HttpDeal::genHeadLine(const std::string &strKey, const std::string &strValue) +{ + std::string strRe = strKey + ": " + strValue + HTTP_SPLIE; + return strRe; +} + +std::string HttpDeal::genDigestAuthenticate(const std::string &realm, std::string &nonce) +{ + std::string strDigest = "Digest realm=\"" + realm + "\"," + "qop=\"auth\"," + "nonce=\"" + + nonce + "\""; + std::string strRe = genHeadLine(Authenticate, strDigest); + return strRe; +} + +HttpDeal::HttpDeal() +{ + httpUrlMap["/home"] = {GET, "/home", std::bind(&HttpDeal::getPage, this)}; + httpUrlMap["/"] = {GET, "/", std::bind(&HttpDeal::getHomePage, this)}; +} + +HttpDeal::~HttpDeal() +{ +} +std::string HttpDeal::genHeadFirstLine(int iCode) +{ + std::string strRe = HTTP_VERSON_HEAD + mapReturnCode[iCode] + HTTP_SPLIE; + return strRe; +} + +int HttpDeal::getHomePage(){ + std::string strHome = "hello home"; + pWriteBuff_->Append(genHeadFirstLine(200)); + pWriteBuff_->Append(genHeadLine(CONTENT_LENGTH, std::to_string(strHome.length()))); + pWriteBuff_->Append(HTTP_SPLIE); + pWriteBuff_->Append(strHome); +} + +int HttpDeal::getPage() +{ + DEBUG_D(pReadBuff_->Peek()); + int iRet = -1; + do + { + if (0 == doDigestAuth()) + { + pWriteBuff_->Append(genHeadFirstLine(200)); + pWriteBuff_->Append(genHeadLine(CONTENT_LENGTH, "0")); + pWriteBuff_->Append(HTTP_SPLIE); + } + else + { + pWriteBuff_->Append(genHeadFirstLine(401)); + pWriteBuff_->Append(genHeadLine(CONTENT_LENGTH, "0")); + pWriteBuff_->Append(HTTP_SPLIE); + } + + } while (0); +} +int HttpDeal::doDigestAuth() +{ + int iRet = -1; + do + { + auto pairAuth = struHttpHead_.mapHeader.find("Authorization"); + if (pairAuth == struHttpHead_.mapHeader.end()) + { + DEBUG_D("WWW-Authenticate" << "no"); + time_t timep; + time(&timep); // 获取从1970至今过了多少秒,存入time_t类型的timep + // printf("%s", ctime(&timep));//用ctime将秒数转化成字符串格式,输出:Thu Feb 28 14:14:17 2019 + std::string strTime = ctime(&timep); + strTime += "abc"; + MD5 MD5Test1; + struHttpDigest_.strNonce = MD5Test1.encode(strTime); + struHttpDigest_.strRealm = "test"; + pWriteBuff_->Append(genHeadFirstLine(401)); + pWriteBuff_->Append(genDigestAuthenticate(struHttpDigest_.strRealm, struHttpDigest_.strNonce)); + pWriteBuff_->Append(genHeadLine(CONTENT_LENGTH, "0")); + pWriteBuff_->Append(HTTP_SPLIE); + iRet = -1; + break; + } + else + { + HTTP_DIGEST_AUTH_T struDigest; + // std::string strUser = "john"; + // std::string strPass = "hello"; + // std::string strHttpAction = "GET"; + std::string strDigest = struHttpHead_.mapHeader["Authorization"]; + httpPraseAuthorization(strDigest, struDigest); + MYSQL *sql; + SqlConnRAII(&sql, SqlConnPool::Instance()); + USER_INFO_T struUserInfo; + sqlQueryUserInfo(sql, struDigest.strUser, struUserInfo); + DEBUG_D(struUserInfo.userName); + DEBUG_D(struUserInfo.passWord); + DEBUG_D("reNonce:" << struDigest.strNonce); + DEBUG_D("Nonce:" << struHttpDigest_.strNonce); + if (0 == struDigest.strNonce.compare(struHttpDigest_.strNonce) && 0 < struHttpDigest_.strNonce.size()) + { + // MD5加密HA1 + MD5 MD5Test1; + std::string strA1 = struUserInfo.userName + ":" + struHttpDigest_.strRealm + ":" + struUserInfo.passWord; + std::string strHA1 = MD5Test1.encode(strA1); + // MD5加密HA2 + MD5 MD5Test2; + std::string strA2 = mapHttpMethod[struHttpHead_.enumMethod] + ":" + struDigest.strUri; + std::string strHA2 = MD5Test2.encode(strA2); + // MD5生成随机数 + time_t timep; + time(&timep); + MD5 MD5Test4; + std::string strRandom = MD5Test4.encode(std::to_string(timep)); + // MD5加密response + MD5 MD5Test3; + std::string strPreResponse = strHA1 + ":" + struHttpDigest_.strNonce + ":" + struDigest.strNc + ":" + struDigest.strCnonce + ":" + struDigest.strQop + ":" + strHA2; + std::string strResponse = MD5Test3.encode(strPreResponse); + DEBUG_D("httpRes:" << strResponse); + DEBUG_D("prehttpRes:" << struDigest.strResponse); + if (0 == strResponse.compare(struDigest.strResponse)) + { + iRet = 0; + break; + } + else + { + iRet = -2; + break; + } + // pWriteBuff_->Append(genHeadFirstLine(200)); + // pWriteBuff_->Append(genHeadLine(CONTENT_LENGTH, "0")); + // pWriteBuff_->Append(HTTP_SPLIE); + } + } + + } while (0); + return iRet; +} + +bool HttpDeal::IsKeepAlive() const +{ + return struHttpHead_.isKeepAlive; +} +int HttpDeal::processHttp() +{ + if (0 == PraseHttpHeader()) + { + pReadBuff_->Retrieve(struHttpHead_.iHeaderLen); + auto findUrl = httpUrlMap.find(struHttpHead_.strPath); + if (findUrl != httpUrlMap.end()) + { + if (findUrl->second.enumMethod == struHttpHead_.enumMethod) + { + findUrl->second.funCallBack(); + }else{ + pWriteBuff_->Append(genHeadFirstLine(405)); + pWriteBuff_->Append(genHeadLine(CONTENT_LENGTH, "0")); + pWriteBuff_->Append(HTTP_SPLIE); + } + } + else + { + if (GET == struHttpHead_.enumMethod){ + processCommonPage(); + }else{ + pWriteBuff_->Append(genHeadFirstLine(405)); + pWriteBuff_->Append(genHeadLine(CONTENT_LENGTH, "0")); + pWriteBuff_->Append(HTTP_SPLIE); + } + + } + + pReadBuff_->RetrieveAll(); + } +} + +int HttpDeal::processCommonPage() +{ + std::string strSrc = "./www"; + strSrc += struHttpHead_.strPath; + DEBUG_D(strSrc); + int iFileRet = access(strSrc.c_str(), F_OK); + if (-1 == iFileRet) + { + pWriteBuff_->Append(genHeadFirstLine(404)); + pWriteBuff_->Append(genHeadLine(CONTENT_LENGTH, "0")); + pWriteBuff_->Append(HTTP_SPLIE); + } + else + { + pWriteBuff_->Append(genHeadFirstLine(200)); + ssize_t iFileSize = getFileSize(strSrc.c_str()); + DEBUG_D(iFileSize); + pWriteBuff_->Append(genHeadLine(CONTENT_LENGTH, std::to_string(iFileSize))); + pWriteBuff_->Append(HTTP_SPLIE); + int fp = open(strSrc.c_str(), O_CREAT | O_RDONLY, S_IRUSR | S_IWUSR); + char buf[1024]; + ssize_t llen = 0; + do + { + memset(buf, 0, 1024); + llen = read(fp, buf, 1024); + DEBUG_D(llen); + pWriteBuff_->Append(buf, llen); + } while (llen > 0); + } +} + +int HttpDeal::PraseHttpHeader() +{ + int iRet = -1; + do + { + + initHeaderStruct(); + std::string strMsg(pReadBuff_->Peek()); + std::regex pattern("(\\w+)\\s+([^\\s]+)\\s+HTTP/([^\\s]+)"); + std::smatch matches; // 用于存储匹配结果 + if (std::regex_search(strMsg, matches, pattern)) + { + if (matches.size() > 2) + { + std::string strMethod = matches[1]; // 请求方法 + std::string strUrl = matches[2]; // 请求的URL + std::string strVersion = matches[3]; + + struHttpHead_.strVersion = strVersion; + struHttpHead_.strPath = strUrl; + DEBUG_D("ver:" << struHttpHead_.strVersion); + DEBUG_I("path" << struHttpHead_.strPath); + for (auto &item : mapHttpMethod) + { + + int index = strMethod.find(item.second); + if (index != std::string::npos) + { + struHttpHead_.enumMethod = item.first; + break; + } + } + } + } + else + { + iRet = -1; + break; + } + std::regex pattern2("([^\\s:]+):\\s*(.*)\r\n"); + std::smatch matches2; // 用于存储匹配结果 + // 使用sregex_iterator来找到所有匹配的子串 + std::sregex_iterator begin = std::sregex_iterator(strMsg.begin(), strMsg.end(), pattern2); + std::sregex_iterator end = std::sregex_iterator(); + // 存储所有匹配的结果 + // std::vector matches; + for (std::sregex_iterator it = begin; it != end; ++it) + { + + std::smatch match = *it; + std::string key = match[1]; // 第一个子匹配(ID) + std::string value = match[2]; // 第二个子匹配(Name) + struHttpHead_.mapHeader[key] = value; + } + for (auto &map : struHttpHead_.mapHeader) + { + DEBUG_I(map.first << " " << map.second); + } + if (struHttpHead_.mapHeader.find("Content-Length") != struHttpHead_.mapHeader.end()) + { + struHttpHead_.iContentLen = atol(struHttpHead_.mapHeader["Content-Length"].c_str()); + DEBUG_I(struHttpHead_.iContentLen); + } + if (struHttpHead_.mapHeader.find("Connection") != struHttpHead_.mapHeader.end()) + { + if (struHttpHead_.mapHeader["Connection"].compare("keep-alive") == 0) + { + struHttpHead_.isKeepAlive = true; + } + else + { + struHttpHead_.isKeepAlive = false; + } + DEBUG_I("keep-alive" << struHttpHead_.isKeepAlive); + } + int iIndex = strMsg.find("\r\n\r\n"); + if (std::string::npos != iIndex) + { + iIndex += 4; + struHttpHead_.iHeaderLen = iIndex; + } + else + { + break; + } + + iRet = 0; + } while (0); + return iRet; +} + +void HttpDeal::init(Buffer *pReadBuff, Buffer *pWriteBuff) +{ + pReadBuff_ = pReadBuff; + pWriteBuff_ = pWriteBuff; +} + +void HttpDeal::initHeaderStruct() +{ + struHttpHead_.enumMethod == NONE; + struHttpHead_.strPath = ""; + struHttpHead_.strVersion = "1.1"; + struHttpHead_.isKeepAlive = false; + struHttpHead_.iHeaderLen = 0; + struHttpHead_.iContentLen = 0; + struHttpHead_.mapHeader.clear(); +} + +int HttpDeal::httpPraseAuthorization(std::string &strAuth, HTTP_DIGEST_AUTH_T &struDigest) +{ + int iRet = 0; + do + { + + findStringKey(strAuth, "username=\"", "\"", struDigest.strUser); + findStringKey(strAuth, "realm=\"", "\"", struDigest.strRealm); + findStringKey(strAuth, "nonce=\"", "\"", struDigest.strNonce); + findStringKey(strAuth, "uri=\"", "\"", struDigest.strUri); + findStringKey(strAuth, "cnonce=\"", "\"", struDigest.strCnonce); + findStringKey(strAuth, "response=\"", "\"", struDigest.strResponse); + } while (0); +} diff --git a/code/http/httpconn.cpp b/code/http/httpconn.cpp index 06778a60..8708dff0 100644 --- a/code/http/httpconn.cpp +++ b/code/http/httpconn.cpp @@ -58,13 +58,29 @@ int HttpConn::GetPort() const { } ssize_t HttpConn::read(int* saveErrno) { + // readBuff_.RetrieveAll(); ssize_t len = -1; do { - len = readBuff_.ReadFd(fd_, saveErrno); - if (len <= 0) { + len = readn(fd_,readBuff_.BeginWrite(),INITBUFFER_SIZE); + if(0>len){ + break; + *saveErrno = errno; + }else if(len == 0){ + break; + } + else + { + /* code */ + readBuff_.HasWritten(len); break; } + + // len = readBuff_.ReadFd(fd_, saveErrno); + // if (len <= 0) { + // break; + // } } while (isET); + // fflush(stdout); return len; } @@ -99,7 +115,7 @@ bool HttpConn::process() { if(readBuff_.ReadableBytes() <= 0) { return false; } - else if(request_.parse(readBuff_)) { + else if(request_.parse(readBuff_,fd_)) { LOG_DEBUG("%s", request_.path().c_str()); response_.Init(srcDir, request_.path(), request_.IsKeepAlive(), 200); } else { diff --git a/code/http/httpconn.h b/code/http/httpconn.h index 1eddb690..39190ce0 100644 --- a/code/http/httpconn.h +++ b/code/http/httpconn.h @@ -18,7 +18,7 @@ #include "../buffer/buffer.h" #include "httprequest.h" #include "httpresponse.h" - +#include "socket.h" class HttpConn { public: HttpConn(); @@ -73,4 +73,4 @@ class HttpConn { }; -#endif //HTTP_CONN_H \ No newline at end of file +#endif //HTTP_CONN_H diff --git a/code/http/httprequest.cpp b/code/http/httprequest.cpp index 69bfbb1e..a63f0acb 100644 --- a/code/http/httprequest.cpp +++ b/code/http/httprequest.cpp @@ -27,8 +27,12 @@ bool HttpRequest::IsKeepAlive() const { return false; } -bool HttpRequest::parse(Buffer& buff) { +bool HttpRequest::parse(Buffer& buff,int iSocketFd) { const char CRLF[] = "\r\n"; + const char CRLFEND[] = "\r\n\r\n"; + const char* lineEnd = search(buff.Peek(), buff.BeginWriteConst(), CRLFEND, CRLFEND + 4); + ssize_t iHeadLen = lineEnd-buff.Peek()+4; + fflush(stdout); if(buff.ReadableBytes() <= 0) { return false; } @@ -50,7 +54,9 @@ bool HttpRequest::parse(Buffer& buff) { } break; case BODY: + ReciveBody_(buff,iSocketFd,iHeadLen); ParseBody_(line); + lineEnd = buff.BeginWrite(); break; default: break; @@ -58,10 +64,41 @@ bool HttpRequest::parse(Buffer& buff) { if(lineEnd == buff.BeginWrite()) { break; } buff.RetrieveUntil(lineEnd + 2); } + buff.RetrieveAll(); LOG_DEBUG("[%s], [%s], [%s]", method_.c_str(), path_.c_str(), version_.c_str()); return true; } +int HttpRequest::ReciveBody_(Buffer& buff,int iSocketFd,ssize_t iHeadLen){ + int iRet = -1; + do + { + std::string strContentLen = "0"; + if(method_ == "POST" &&header_.count("Content-Length") == 1) { + strContentLen = header_.find("Content-Length")->second; + ssize_t iConLen = atol(strContentLen.c_str()); + iConLen -= INITBUFFER_SIZE-iHeadLen; + char buf[512]; + while (iConLen>0) + { + memset(buf,0,512); + /* code */ + int iLen = readn(iSocketFd,buf,512); + buff.Append(buf,iLen); + iConLen-=iLen; + } + fflush(stdout); + + } + + state_ = BODY; + iRet = 0; + } while (0); + + return iRet; + +} + void HttpRequest::ParsePath_() { if(path_ == "/") { path_ = "/index.html"; @@ -131,8 +168,13 @@ void HttpRequest::ParsePost_() { } } } + if(method_ == "POST" && header_["Content-Type"] == "application/x-www-form-urlencoded") { + + } } + + void HttpRequest::ParseFromUrlencoded_() { if(body_.size() == 0) { return; } @@ -264,4 +306,4 @@ std::string HttpRequest::GetPost(const char* key) const { return post_.find(key)->second; } return ""; -} \ No newline at end of file +} diff --git a/code/http/httprequest.h b/code/http/httprequest.h index d1652b21..04b31db2 100644 --- a/code/http/httprequest.h +++ b/code/http/httprequest.h @@ -17,7 +17,8 @@ #include "../log/log.h" #include "../pool/sqlconnpool.h" #include "../pool/sqlconnRAII.h" - +#include "socket.h" +#include "../cJson/cJSON.h" class HttpRequest { public: enum PARSE_STATE { @@ -42,7 +43,7 @@ class HttpRequest { ~HttpRequest() = default; void Init(); - bool parse(Buffer& buff); + bool parse(Buffer& buff,int iSocketFd); std::string path() const; std::string& path(); @@ -63,7 +64,7 @@ class HttpRequest { bool ParseRequestLine_(const std::string& line); void ParseHeader_(const std::string& line); void ParseBody_(const std::string& line); - + int ReciveBody_(Buffer& buff,int iSocketFd,ssize_t iHeadLen); void ParsePath_(); void ParsePost_(); void ParseFromUrlencoded_(); @@ -81,4 +82,4 @@ class HttpRequest { }; -#endif //HTTP_REQUEST_H \ No newline at end of file +#endif //HTTP_REQUEST_H diff --git a/code/log/log.cpp b/code/log/log.cpp index 32ccf9b5..0abc6210 100644 --- a/code/log/log.cpp +++ b/code/log/log.cpp @@ -2,12 +2,13 @@ * @Author : mark * @Date : 2020-06-16 * @copyleft Apache 2.0 - */ + */ #include "log.h" using namespace std; -Log::Log() { +Log::Log() +{ lineCount_ = 0; isAsync_ = false; writeThread_ = nullptr; @@ -16,45 +17,56 @@ Log::Log() { fp_ = nullptr; } -Log::~Log() { - if(writeThread_ && writeThread_->joinable()) { - while(!deque_->empty()) { +Log::~Log() +{ + if (writeThread_ && writeThread_->joinable()) + { + while (!deque_->empty()) + { deque_->flush(); }; deque_->Close(); writeThread_->join(); } - if(fp_) { + if (fp_) + { lock_guard locker(mtx_); flush(); fclose(fp_); } } -int Log::GetLevel() { +int Log::GetLevel() +{ lock_guard locker(mtx_); return level_; } -void Log::SetLevel(int level) { +void Log::SetLevel(int level) +{ lock_guard locker(mtx_); level_ = level; } -void Log::init(int level = 1, const char* path, const char* suffix, - int maxQueueSize) { +void Log::init(int level = 1, const char *path, const char *suffix, + int maxQueueSize) +{ isOpen_ = true; level_ = level; - if(maxQueueSize > 0) { + if (maxQueueSize > 0) + { isAsync_ = true; - if(!deque_) { + if (!deque_) + { unique_ptr> newDeque(new BlockDeque); deque_ = move(newDeque); - + std::unique_ptr NewThread(new thread(FlushLogThread)); writeThread_ = move(NewThread); } - } else { + } + else + { isAsync_ = false; } @@ -66,28 +78,31 @@ void Log::init(int level = 1, const char* path, const char* suffix, path_ = path; suffix_ = suffix; char fileName[LOG_NAME_LEN] = {0}; - snprintf(fileName, LOG_NAME_LEN - 1, "%s/%04d_%02d_%02d%s", - path_, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, suffix_); + snprintf(fileName, LOG_NAME_LEN - 1, "%s/%04d_%02d_%02d%s", + path_, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, suffix_); toDay_ = t.tm_mday; { lock_guard locker(mtx_); buff_.RetrieveAll(); - if(fp_) { + if (fp_) + { flush(); - fclose(fp_); + fclose(fp_); } fp_ = fopen(fileName, "a"); - if(fp_ == nullptr) { + if (fp_ == nullptr) + { mkdir(path_, 0777); fp_ = fopen(fileName, "a"); - } + } assert(fp_ != nullptr); } } -void Log::write(int level, const char *format, ...) { +void Log::write(int level, const char *pcFileName, int iLine, const char *pcFunction, const char *format, ...) +{ struct timeval now = {0, 0}; gettimeofday(&now, nullptr); time_t tSec = now.tv_sec; @@ -96,11 +111,11 @@ void Log::write(int level, const char *format, ...) { va_list vaList; /* 日志日期 日志行数 */ - if (toDay_ != t.tm_mday || (lineCount_ && (lineCount_ % MAX_LINES == 0))) + if (toDay_ != t.tm_mday || (lineCount_ && (lineCount_ % MAX_LINES == 0))) { unique_lock locker(mtx_); locker.unlock(); - + char newFile[LOG_NAME_LEN]; char tail[36] = {0}; snprintf(tail, 36, "%04d_%02d_%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday); @@ -111,10 +126,11 @@ void Log::write(int level, const char *format, ...) { toDay_ = t.tm_mday; lineCount_ = 0; } - else { - snprintf(newFile, LOG_NAME_LEN - 72, "%s/%s-%d%s", path_, tail, (lineCount_ / MAX_LINES), suffix_); + else + { + snprintf(newFile, LOG_NAME_LEN - 72, "%s/%s-%d%s", path_, tail, (lineCount_ / MAX_LINES), suffix_); } - + locker.lock(); flush(); fclose(fp_); @@ -126,12 +142,16 @@ void Log::write(int level, const char *format, ...) { unique_lock locker(mtx_); lineCount_++; int n = snprintf(buff_.BeginWrite(), 128, "%d-%02d-%02d %02d:%02d:%02d.%06ld ", - t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, - t.tm_hour, t.tm_min, t.tm_sec, now.tv_usec); - + t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, + t.tm_hour, t.tm_min, t.tm_sec, now.tv_usec); + buff_.HasWritten(n); AppendLogLevelTitle_(level); + n = snprintf(buff_.BeginWrite(),128,"[%s:%d][%s]\t", + pcFileName, iLine,pcFunction); + buff_.HasWritten(n); + va_start(vaList, format); int m = vsnprintf(buff_.BeginWrite(), buff_.WritableBytes(), format, vaList); va_end(vaList); @@ -139,17 +159,22 @@ void Log::write(int level, const char *format, ...) { buff_.HasWritten(m); buff_.Append("\n\0", 2); - if(isAsync_ && deque_ && !deque_->full()) { + if (isAsync_ && deque_ && !deque_->full()) + { deque_->push_back(buff_.RetrieveAllToStr()); - } else { + } + else + { fputs(buff_.Peek(), fp_); } buff_.RetrieveAll(); } } -void Log::AppendLogLevelTitle_(int level) { - switch(level) { +void Log::AppendLogLevelTitle_(int level) +{ + switch (level) + { case 0: buff_.Append("[debug]: ", 9); break; @@ -168,26 +193,32 @@ void Log::AppendLogLevelTitle_(int level) { } } -void Log::flush() { - if(isAsync_) { - deque_->flush(); +void Log::flush() +{ + if (isAsync_) + { + deque_->flush(); } fflush(fp_); } -void Log::AsyncWrite_() { +void Log::AsyncWrite_() +{ string str = ""; - while(deque_->pop(str)) { + while (deque_->pop(str)) + { lock_guard locker(mtx_); fputs(str.c_str(), fp_); } } -Log* Log::Instance() { +Log *Log::Instance() +{ static Log inst; return &inst; } -void Log::FlushLogThread() { +void Log::FlushLogThread() +{ Log::Instance()->AsyncWrite_(); -} \ No newline at end of file +} diff --git a/code/log/log.h b/code/log/log.h index c26b3cdb..c69de835 100644 --- a/code/log/log.h +++ b/code/log/log.h @@ -16,7 +16,7 @@ #include //mkdir #include "blockqueue.h" #include "../buffer/buffer.h" - +#include class Log { public: void init(int level, const char* path = "./log", @@ -26,7 +26,7 @@ class Log { static Log* Instance(); static void FlushLogThread(); - void write(int level, const char *format,...); + void write(int level, const char* pcFileName, int iLine, const char* pcFunction, const char *format,...); void flush(); int GetLevel(); @@ -63,12 +63,12 @@ class Log { std::unique_ptr writeThread_; std::mutex mtx_; }; - +#define FILENAME(x) strchr(x,'/')?strrchr(x,'/')+1:x #define LOG_BASE(level, format, ...) \ do {\ Log* log = Log::Instance();\ if (log->IsOpen() && log->GetLevel() <= level) {\ - log->write(level, format, ##__VA_ARGS__); \ + log->write(level,FILENAME(__FILE__) ,__LINE__,__func__, format, ##__VA_ARGS__); \ log->flush();\ }\ } while(0); @@ -78,4 +78,4 @@ class Log { #define LOG_WARN(format, ...) do {LOG_BASE(2, format, ##__VA_ARGS__)} while(0); #define LOG_ERROR(format, ...) do {LOG_BASE(3, format, ##__VA_ARGS__)} while(0); -#endif //LOG_H \ No newline at end of file +#endif //LOG_H