Files
LayaNative2.0/Conch/source/common/downloadMgr/JCHttpHeader.cpp
T
2020-11-11 16:17:13 +08:00

245 lines
7.2 KiB
C++

/**
@file JCHttpHeader.cpp
@brief
@author guo
@version 1.0
@date 2016_09_03
*/
#include "JCHttpHeader.h"
#include "../util/Log.h"
#include "../util/JCCommonMethod.h"
#include "../util/JCCrypto.h"
#include <stdlib.h>
#define peek(buf, c1) *(buf+1) != '\0' && *(buf+1) == c1
#define peek2(buf, c1, c2) \
*(buf+1) != '\0' && *(buf+1) == c1 \
*(buf+2) != '\0' && *(buf+2) == c2
#define iscrlf(p) (*p == '\r' && *(p + 1) == '\n')
#define notcrlf(p) (*p != '\r' && *(p + 1) != '\n')
#define notend(p) (*p != '\0')
#define end(p) (*p == '\0')
#define H3_DEFAULT_HTTP_VERSION "HTTP/1.0"
namespace laya{
/**
* This function returns a char pointer, which is the end of the request line.
*
* Return NULL if parse failed.
*/
const char * JCHttpHeader::request_line_parse(RequestHeader *header, const char *body, int bodyLength) {
// Parse the request-line
// http://tools.ietf.org/html/rfc2616#section-5.1
// Request-Line = Method SP Request-URI SP HTTP-Version CRLF
const char * p = body;
header->RequestLineStart = body;
while (notend(p) && !isspace(*p)) p++;
if (end(p) || iscrlf(p)) {
// set error
return NULL;
}
header->RequestMethod = body;
header->RequestMethodLen = p - body;
// Skip space
// parse RequestURI
while (isspace(*p) && notcrlf(p) && notend(p)) p++;
header->RequestURI = p;
while (!isspace(*p) && notcrlf(p) && notend(p)) p++;
header->RequestURILen = p - header->RequestURI;
// Skip space and parse HTTP-Version
if (iscrlf(p) || end(p)) {
header->HTTPVersion = H3_DEFAULT_HTTP_VERSION;
}
else {
while (isspace(*p) && notcrlf(p)) p++;
header->HTTPVersion = p;
while (!isspace(*p) && notcrlf(p)) p++;
header->HTTPVersionLen = p - header->HTTPVersion;
}
return p;
}
/**
* Parse header body
*/
int JCHttpHeader::request_header_parse(RequestHeader *header, const char *body, int bodyLength) {
const char *p = request_line_parse(header, body, bodyLength);
if (p == NULL) {
return ERR_REQUEST_LINE_PARSE_FAIL;
}
// should be ended with CR-LF
if (end(p)) return -1;
// skip CR-LF
iscrlf(p); p += 2;
if (end(p)) return 0;
header->HeaderSize = 0;
// Parse Header Fields Here
do {
HeaderField *field = &header->Fields[header->HeaderSize++];
// HeaderField *field = h3_header_field_new();
field->FieldName = p; // start of a header field name
while (notend(p) && *p != ':') p++;
field->FieldNameLen = p - field->FieldName;
p++; // skip ':'
// CRLF is not allowed here
if (end(p) || iscrlf(p)) return -1;
while (notend(p) && isspace(*p)) p++; // skip space
// CRLF is not allowed here
if (end(p) || iscrlf(p)) return -1;
field->Value = p;
while (notend(p) && notcrlf(p)) p++;
field->ValueLen = p - field->Value + 1;
iscrlf(p); p += 2;
#ifdef _DEBUG
printf("==> %.*s ==> %.*s\n", field->FieldNameLen, field->FieldName, field->ValueLen, field->Value);
#endif
// end of header
if (iscrlf(p)) return 0;
} while (notend(p) && header->HeaderSize < MAX_FILED_NUM);
return 0;
}
constexpr int _First_Len(char v1, int len) {
return (((int)v1) << 8) | len;
}
JCHttpHeader::JCHttpHeader(const char* pHeader) {
m_bCacheContrl = false;
request_header_parse(this, pHeader, strlen(pHeader));
for (int i = 0; i < (int)HeaderSize; i++) {
HeaderField& cfield = Fields[i];
int id = (cfield.FieldName[0] << 8)|(cfield.FieldNameLen & 0xff);
switch (id) {
case _First_Len('C',12)://Content-Type
if (memcmp(cfield.FieldName + 1, "ontent-Type",11) == 0) {
int a = 0;
}
break;
case _First_Len('C',13)://Cache-Control
if (memcmp(cfield.FieldName + 1, "ache-Control",12) == 0) {
parseCacheControl((char*)cfield.Value, cfield.ValueLen);
}
break;
case _First_Len('C',14)://Content-Length
if (memcmp(cfield.FieldName + 1, "ontent-Length", 13) == 0) {
int a = 0;
}
break;
case _First_Len('E',4):
break;
case _First_Len('E',7):
break;
}
}
}
int _getTokeHash(const char*& pDt) {
const char* pst = pDt;
while (*pDt != ',' && *pDt != ' '&& *pDt!='=' && *pDt != 0) {
*pDt++;
}
return JCBKDRHash::hashMem((const unsigned char*)pst, pDt-pst);
}
void _getSplit(const char*& pDt) {
while (*pDt == ',' || *pDt == ' ' ||*pDt=='=')
pDt++;
}
int _getNumber(const char*& pDt) {
const char* pSt = pDt;
char number[16] = { 0 };
while (*pDt >= '0' && *pDt <= '9') {
pDt++;
}
if (pDt - pSt > sizeof(number)) {
LOGE("parseCacheControl error");
*(int*)0 = 1;//报错
}
memcpy(number, pSt, pDt - pSt);
return atoi(number);
}
bool JCHttpHeader::parseCacheControl(char* p_pStr, int p_len) {
char* cp = new char[p_len + 1];
memcpy(cp, p_pStr, p_len);
cp[p_len] = 0; //最后用0比较容易处理。
const char* pDt = cp;
while (*pDt != 0) {//
int hash = _getTokeHash(pDt);
switch (hash){
case 0x7dbba7b2://max-age
pDt++;
m_CacheControl.maxage = _getNumber(pDt);
break;
case 0x4fbcb749://no-store
m_CacheControl.nostore = true;
_getSplit(pDt);
break;
case 0x3452662e://no-cache
m_CacheControl.nocache = true;
_getSplit(pDt);
break;
case 0x19fb0881://must-revalidate
_getSplit(pDt);
break;
default:
_getSplit(pDt);
break;
}
}
delete[] cp;
return true;
}
const char* JCHttpHeader::getLastModifyed() {//"Last-Modified"
return "";
}
const char* JCHttpHeader::getPragma() {//"Pragma"
return "";
}
const char* JCHttpHeader::getContentType() {//"Content-Type"
return "";
}
const char* JCHttpHeader::getETag() {//"ETag"
return "";
}
int64_t JCHttpHeader::getExpires() {
static const char* strExpires = "Expires";
if (m_tmExpires != 0)
return m_tmExpires;
for (int i = 0; i < (int)HeaderSize; i++) {
HeaderField& cfield = Fields[i];
if (memcmp(cfield.FieldName, strExpires, strlen(strExpires)) == 0) {
//return
}
}
return 0;
}
}