static inline int method_lookup(struct mk_http_request *req, struct mk_http_parser *p, char *buffer) { int i = 0; int len; /* Method lenght */ len = field_len(); /* Point the buffer */ req->method = MK_METHOD_UNKNOWN; req->method_p.data = buffer + p->start; req->method_p.len = len; if (p->method >= 0) { if (strncmp(buffer + p->start + 1, mk_methods_table[p->method].name + 1, len - 1) == 0) { req->method = p->method; return req->method; } } for (i = 0; i < MK_METHOD_SIZEOF; i++) { if (len != mk_methods_table[i].len) { continue; } if (strncmp(buffer + p->start, mk_methods_table[i].name, len) == 0) { req->method = i; return i; } } return MK_METHOD_UNKNOWN; }
int get_url(unsigned char* buf, int *url_len, const unsigned char *pkt_data, int hdr_len) { const unsigned char* cur; int host_len; int uri_len; memcpy(buf, "http://", 7); buf += 7; *url_len = 7; cur = strstr(pkt_data, "Host:"); if (cur == NULL) return -1; cur += 6; host_len = field_len(cur, hdr_len - (cur - pkt_data)); if (host_len && (*url_len +host_len<1200)){ memcpy(buf, cur, host_len); buf += host_len; *url_len += host_len; } else { return -1; } cur = pkt_data; if (pkt_data[0] == 'G') cur += 4; else if (pkt_data[0] == 'P'){ cur += 5; } uri_len = field_len(cur, hdr_len - (cur - pkt_data)); uri_len -= 9; if((*url_len + uri_len) < 1200){ memcpy(buf, cur, uri_len); *url_len += uri_len; } return 0; }
uint8_t parse_gps_rmc(gps_rmc_state_t * state) { if (gps_message_type() != GPS_MESSAGE_GPRMC) return E_MSG_TYPE_ERR; uint8_t *parse_buffer[16]; uint8_t i, len; state->hour = atos_len(gps_data + GPS_RMC_HOUR_OFFSET, 2); state->minute = atos_len(gps_data + GPS_RMC_MINUTE_OFFSET, 2); state->second = atos_len(gps_data + GPS_RMC_SECOND_OFFSET, 2); if (gps_data[GPS_RMC_VALID_OFFSET] == 'A') { state->flags &= ~GPS_DATA_INVALID; } else { state->flags |= GPS_DATA_INVALID; } state->latitude_degrees = atos_len(gps_data + GPS_RMC_LATITUDE_DEG_OFFSET, 2); state->latitude_seconds = atos_len(gps_data + GPS_RMC_LATITUDE_MIN_VAL_OFFSET, 2) * 10000; state->latitude_seconds += atos_len(gps_data + GPS_RMC_LATITUDE_MIN_FRAC_OFFSET, 4); state->flags &= ~(LATITUDE_N | LATITUDE_S); if (gps_data[GPS_RMC_LATITUDE_NS_OFFSET] == 'N') { state->flags |= LATITUDE_N; } else if (gps_data[GPS_RMC_LATITUDE_NS_OFFSET] == 'S') { state->flags |= LATITUDE_S; } state->longitude_degrees = atos_len(gps_data + GPS_RMC_LONGITUDE_DEG_OFFSET, 3); state->longitude_seconds = atos_len(gps_data + GPS_RMC_LONGITUDE_MIN_VAL_OFFSET, 2) * 10000; state->longitude_seconds += atos_len(gps_data + GPS_RMC_LONGITUDE_MIN_FRAC_OFFSET, 4); state->flags &= ~(LONGITUDE_E | LONGITUDE_W); if (gps_data[GPS_RMC_LONGITUDE_EW_OFFSET] == 'E') { state->flags |= LONGITUDE_E; } else if (gps_data[GPS_RMC_LONGITUDE_EW_OFFSET] == 'W') { state->flags |= LONGITUDE_W; } i = GPS_RMC_SPEED_OFFSET; len = field_len(gps_data + i); if (len != 0) { state->speed = atos_len(gps_data + i, len) * 100; i += len + 1; len = field_len(gps_data + i); if (len != 0) { state->speed += atos_len(gps_data + i, len); } i += len + 1; } else { i++; state->speed = 0; } len = field_len(gps_data + i); if (len != 0) { state->course = atos_len(gps_data + i, len) * 100; i += len + 1; len = field_len(gps_data + i); if (len != 0) { state->course += atos_len(gps_data + i, len); } i += len + 1; } else { i++; state->course = 0; } // Set data state->day = atos_len(gps_data + i, 2); i += 2; state->month = atos_len(gps_data + i, 2); i += 2; state->year = atos_len(gps_data + i, 2); /* sdWrite(&SD1, "RMC PARSED:", sizeof("RMC PARSED:") - 1); SPRNT(state->hour, "Hour: ", 1); SPRNT(state->minute, "Minute: ", 1); SPRNT(state->second, "Second: ", 1); SPRNT(state->day, "Day: ", 1); SPRNT(state->month, "Month: ", 1); SPRNT(state->year, "Year: ", 1); SPRNT(state->speed, "Speed: ", 1); SPRNT(state->course, "Course: ", 1); SPRNT(state->flags, "Flags: ", 1); SPRNT(state->latitude_degrees, "Lat degrees: ", 1); SPRNT(state->latitude_seconds/10000, "Lat seconds: ", 1); SPRNT(state->latitude_seconds % 10000, "Lat seconds: ", 1); SPRNT(state->longitude_degrees, "Long degrees: ", 1); SPRNT(state->longitude_seconds/10000, "Long seconds: ", 1); SPRNT(state->longitude_seconds % 10000, "Long seconds: ", 1); */ return E_OK; }
/* * Parse the protocol and point relevant fields, don't take logic decisions * based on this, just parse to locate things. */ int mk_http_parser(struct mk_http_request *req, struct mk_http_parser *p, char *buffer, int buf_len, struct mk_server *server) { int s; int tmp; int ret; int len; /* lazy test printf("p->i=%i buf_len=%i\n", p->i, buf_len); for (s = p->i; s < buf_len; s++) { if (buffer[s] == '\r') { printf("CR"); } else if (buffer[s] == '\n') { printf("LF"); } else { printf("%c", buffer[s]); } } printf("\n"); */ len = buf_len; for (; p->i < len; p->i++, p->chars++) { /* FIRST LINE LEVEL: Method, URI & Protocol */ if (p->level == REQ_LEVEL_FIRST) { switch (p->status) { case MK_ST_REQ_METHOD: /* HTTP Method */ if (p->chars == -1) { switch (buffer[p->i]) { case 'G': p->method = MK_METHOD_GET; break; case 'P': p->method = MK_METHOD_POST; break; case 'H': p->method = MK_METHOD_HEAD; break; case 'D': p->method = MK_METHOD_DELETE; break; case 'O': p->method = MK_METHOD_OPTIONS; break; } continue; } if (buffer[p->i] == ' ') { mark_end(); p->status = MK_ST_REQ_URI; if (p->end < 2) { return MK_HTTP_PARSER_ERROR; } method_lookup(req, p, buffer); start_next(); } else { if ((p->i - p->start) > 10) { return MK_HTTP_PARSER_ERROR; } } break; case MK_ST_REQ_URI: /* URI */ if (buffer[p->i] == ' ') { mark_end(); p->status = MK_ST_REQ_PROT_VERSION; if (field_len() < 1) { return MK_HTTP_PARSER_ERROR; } request_set(&req->uri, p, buffer); start_next(); } else if (buffer[p->i] == '?') { mark_end(); request_set(&req->uri, p, buffer); p->status = MK_ST_REQ_QUERY_STRING; start_next(); } else if (buffer[p->i] == '\r' || buffer[p->i] == '\n') { mk_http_error(MK_CLIENT_BAD_REQUEST, req->session, req, server); return MK_HTTP_PARSER_ERROR; } break; case MK_ST_REQ_QUERY_STRING: /* Query string */ char_lookup(buffer, ' ', len, p); if (buffer[p->i] == ' ') { mark_end(); request_set(&req->query_string, p, buffer); p->status = MK_ST_REQ_PROT_VERSION; start_next(); } else if (buffer[p->i] == '\r' || buffer[p->i] == '\n') { mk_http_error(MK_CLIENT_BAD_REQUEST, req->session, req, server); return MK_HTTP_PARSER_ERROR; } break; case MK_ST_REQ_PROT_VERSION: /* Protocol Version */ /* * Most of the time we already have the string version in our * buffer, for that case try to match the version and avoid * loop rounds. */ if (p->start + 6 >= p->i) { continue; } tmp = p->start; if (buffer[tmp] == 'H' && buffer[tmp + 1] == 'T' && buffer[tmp + 2] == 'T' && buffer[tmp + 3] == 'P' && buffer[tmp + 4] == '/' && buffer[tmp + 5] == '1' && buffer[tmp + 6] == '.') { request_set(&req->protocol_p, p, buffer); req->protocol_p.len = 8; mk_http_set_minor_version(buffer[tmp + 7]); } else { mk_http_error(MK_SERVER_HTTP_VERSION_UNSUP, req->session, req, server); return MK_HTTP_PARSER_ERROR; } p->status = MK_ST_FIRST_CONTINUE; break; case MK_ST_FIRST_CONTINUE: if (buffer[p->i] == '\r') { p->status = MK_ST_FIRST_FINALIZING; } else { return MK_HTTP_PARSER_ERROR; } break; case MK_ST_FIRST_FINALIZING: /* New Line */ if (buffer[p->i] == '\n') { p->level = REQ_LEVEL_CONTINUE; start_next(); } else { return MK_HTTP_PARSER_ERROR; } break; case MK_ST_BLOCK_END: if (buffer[p->i] == '\n') { return mk_http_parser_ok(req, p, server); } else { return MK_HTTP_PARSER_ERROR; } break; }; } else if (p->level == REQ_LEVEL_CONTINUE) { if (buffer[p->i] == '\r') { p->level = REQ_LEVEL_FIRST; p->status = MK_ST_BLOCK_END; } else { p->level = REQ_LEVEL_HEADERS; p->status = MK_ST_HEADER_KEY; p->chars = 0; } } /* HEADERS: all headers stuff */ if (p->level == REQ_LEVEL_HEADERS) { /* Expect a Header key */ if (p->status == MK_ST_HEADER_KEY) { if (buffer[p->i] == '\r') { if (p->chars == 0) { p->level = REQ_LEVEL_END; start_next(); } else { return MK_HTTP_PARSER_ERROR; } } if (p->chars == 0) { /* * We reach the start of a Header row, lets catch the most * probable header. * * The goal of this 'first row character lookup', is to define a * small range set of probable headers comparison once we catch * a header end. */ s = tolower(buffer[p->i]); switch (s) { case 'a': p->header_min = MK_HEADER_ACCEPT; p->header_max = MK_HEADER_AUTHORIZATION; break; case 'c': p->header_min = MK_HEADER_CACHE_CONTROL; p->header_max = MK_HEADER_CONTENT_TYPE; break; case 'h': p->header_min = MK_HEADER_HOST; p->header_max = MK_HEADER_HTTP2_SETTINGS; break; case 'i': header_scope_eq(p, MK_HEADER_IF_MODIFIED_SINCE); break; case 'l': p->header_min = MK_HEADER_LAST_MODIFIED; p->header_max = MK_HEADER_LAST_MODIFIED_SINCE; break; case 'r': p->header_min = MK_HEADER_RANGE; p->header_max = MK_HEADER_REFERER; break; case 'u': p->header_min = MK_HEADER_UPGRADE; p->header_max = MK_HEADER_USER_AGENT; break; default: p->header_key = -1; p->header_sep = -1; p->header_min = -1; p->header_max = -1; }; p->header_key = p->i; continue; } /* Found key/value separator */ char_lookup(buffer, ':', len, p); if (buffer[p->i] == ':') { /* Set the key/value middle point */ p->header_sep = p->i; /* validate length */ mark_end(); if (field_len() < 1) { return MK_HTTP_PARSER_ERROR; } /* Wait for a value */ p->status = MK_ST_HEADER_VALUE; start_next(); } } /* Parsing the header value */ else if (p->status == MK_ST_HEADER_VALUE) { /* Trim left, set starts only when found something != ' ' */ if (buffer[p->i] == '\r' || buffer[p->i] == '\n') { return MK_HTTP_PARSER_ERROR; } else if (buffer[p->i] != ' ') { p->status = MK_ST_HEADER_VAL_STARTS; p->start = p->header_val = p->i; } continue; } /* New header row starts */ else if (p->status == MK_ST_HEADER_VAL_STARTS) { /* Maybe there is no more headers and we reach the end ? */ if (buffer[p->i] == '\r') { mark_end(); if (field_len() <= 0) { return MK_HTTP_PARSER_ERROR; } /* * A header row has ended, lets lookup the header and populate * our headers table index. */ ret = header_lookup(p, buffer); if (ret != 0) { if (ret < -1) { mk_http_error(-ret, req->session, req, server); } return MK_HTTP_PARSER_ERROR; } /* Try to catch next LF */ if (p->i + 1 < len) { if (buffer[p->i + 1] == '\n') { p->i++; p->status = MK_ST_HEADER_KEY; p->chars = -1; start_next(); } } p->status = MK_ST_HEADER_END; start_next(); } else if (buffer[p->i] == '\n' && buffer[p->i - 1] != '\r') { return MK_HTTP_PARSER_ERROR; } } else if (p->status == MK_ST_HEADER_END) { if (buffer[p->i] == '\n') { p->status = MK_ST_HEADER_KEY; p->chars = -1; start_next(); } else { return MK_HTTP_PARSER_ERROR; } } } else if (p->level == REQ_LEVEL_END) { if (buffer[p->i] == '\n') { if (p->header_content_length > 0) { p->level = REQ_LEVEL_BODY; p->chars = -1; start_next(); } else { return mk_http_parser_ok(req, p, server); } } else { return MK_HTTP_PARSER_ERROR; } } else if (p->level == REQ_LEVEL_BODY) { /* * Reaching this level can means two things: * * - A Pipeline Request * - A Body content (POST/PUT methods) */ if (p->header_content_length > 0) { p->body_received = len - p->start; if ((len - p->start) < p->header_content_length) { return MK_HTTP_PARSER_PENDING; } /* Cut off */ p->i += p->body_received; req->data.len = p->body_received; req->data.data = (buffer + p->start); } return mk_http_parser_ok(req, p, server); } } return MK_HTTP_PARSER_PENDING; }
static inline void request_set(mk_ptr_t *ptr, struct mk_http_parser *p, char *buffer) { ptr->data = buffer + p->start; ptr->len = field_len(); }