void ShellTaskInit() { TaskHandle_t xHandle = NULL; read_line_init(&read_line_config); ConsoleInit(); xTaskCreate(ShellTask, "shell", configMINIMAL_STACK_SIZE + 200, NULL, 1, &xHandle); assert(xHandle); }
/** * read http reply * * TODO: use a callback instead of expect_data * * @param conn * @param expect_data // always set to 1, expect for HEAD-like methods! * @param http_statusp returns the http status * @param header_func * @param buffer_func * @param cb_arg * * @return dpl_status */ dpl_status_t dpl_read_http_reply_buffered(dpl_conn_t *conn, int expect_data, int *http_statusp, dpl_header_func_t header_func, dpl_buffer_func_t buffer_func, void *cb_arg) { int ret, ret2; struct dpl_http_reply http_reply; char *line = NULL; size_t chunk_len = 0; ssize_t chunk_remain = 0; ssize_t chunk_off = 0; int chunked = 0; #define MODE_REPLY 0 #define MODE_HEADER 1 #define MODE_CHUNK 2 #define MODE_CHUNKED 3 int mode; DPRINTF("read_http_reply fd=%d flags=0x%x\n", conn->fd, flags); http_reply.code = 0; read_line_init(conn); mode = MODE_REPLY; ret = DPL_SUCCESS; while (1) { if (MODE_CHUNK == mode) { DPRINTF("chunk_len=%ld chunk_off=%ld\n", chunk_len, chunk_off); if (chunk_off < chunk_len) { chunk_remain = chunk_len - chunk_off; DPL_TRACE(conn->ctx, DPL_TRACE_IO, "read conn=%p https=%d size=%ld (remain %ld)", conn, conn->ctx->use_https, conn->read_buf_size, chunk_remain); if (0 == conn->ctx->use_https) { struct pollfd fds; int recvfl = 0; retry: memset(&fds, 0, sizeof (fds)); fds.fd = conn->fd; fds.events = POLLIN; ret2 = poll(&fds, 1, conn->ctx->read_timeout*1000); if (-1 == ret2) { if (errno == EINTR) goto retry; DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "poll"); ret = DPL_FAILURE; goto end; } if (0 == ret2) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "read timeout"); ret = DPL_FAILURE; goto end; } else if (!(fds.revents & POLLIN)) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "socket error"); ret = DPL_FAILURE; goto end; } recvfl = (chunk_remain >= conn->read_buf_size) ? MSG_WAITALL : 0; conn->cc = recv(conn->fd, conn->read_buf, conn->read_buf_size, recvfl); if (-1 == conn->cc) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "recv"); ret = DPL_FAILURE; goto end; } } else { conn->cc = SSL_read(conn->ssl, conn->read_buf, conn->read_buf_size); if (conn->cc <= 0) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "SSL_read"); ret = DPL_FAILURE; goto end; } } DPL_TRACE(conn->ctx, DPL_TRACE_IO, "read conn=%p https=%d cc=%ld", conn, conn->ctx->use_https, conn->cc); if (0 == conn->cc) { DPRINTF("no more data to read\n"); break ; } if (conn->ctx->trace_buffers) dpl_dump_simple(conn->read_buf, conn->cc, conn->ctx->trace_binary); chunk_remain = MIN(conn->cc, chunk_len - chunk_off); ret2 = buffer_func(cb_arg, conn->read_buf, chunk_remain); if (DPL_SUCCESS != ret2) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "buffer_func"); ret = DPL_FAILURE; goto end; } conn->read_buf_pos = chunk_remain; chunk_off += chunk_remain; continue ; } DPL_TRACE(conn->ctx, DPL_TRACE_HTTP, "conn=%p chunk done", conn); if (1 == chunked) { mode = MODE_HEADER; //skip crlf continue ; } else { ret = DPL_SUCCESS; break ; } } else { line = read_line(conn); if (NULL == line) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "read line: %s", dpl_status_str(conn->status)); ret = DPL_FAILURE; goto end; } switch (mode) { case MODE_REPLY: if (http_parse_reply(line, &http_reply) != 0) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "bad http reply: %.*s...", 100, line); ret = DPL_FAILURE; goto end; } DPL_TRACE(conn->ctx, DPL_TRACE_HTTP, "conn=%p http_status=%d", conn, http_reply.code); mode = MODE_HEADER; break ; case MODE_HEADER: if (line[0] == '\r') { if (1 == chunked) { mode = MODE_CHUNKED; } else { //one big chunk mode = MODE_CHUNK; chunk_off = 0; if (conn->read_buf_pos < conn->cc) { chunk_remain = MIN(conn->cc - conn->read_buf_pos, chunk_len); ret2 = buffer_func(cb_arg, conn->read_buf + conn->read_buf_pos, chunk_remain); if (DPL_SUCCESS != ret2) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "buffer_func"); ret = DPL_FAILURE; goto end; } conn->read_buf_pos += chunk_remain; chunk_off += chunk_remain; } } break ; } //headers { char *p, *p2; p = index(line, ':'); if (NULL == p) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "bad header: %.*s...", 100, line); break ; } *p++ = 0; //skip ws for (;*p;p++) if (!isspace(*p)) break ; //remove '\r' p2 = index(p, '\r'); if (NULL != p2) *p2 = 0; DPL_TRACE(conn->ctx, DPL_TRACE_HTTP, "conn=%p header='%s' value='%s'", conn, line, p); if (expect_data && !strcasecmp(line, "Content-Length")) { chunk_len = atoi(p); } else if (!strcasecmp(line, "Transfer-Encoding")) { if (expect_data) { if (!strcasecmp(p, "chunked")) chunked = 1; } } else { ret2 = header_func(cb_arg, line, p); if (DPL_SUCCESS != ret2) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "header_func"); ret = DPL_FAILURE; goto end; } } break ; } case MODE_CHUNKED: chunk_len = strtoul(line, NULL, 16); DPL_TRACE(conn->ctx, DPL_TRACE_IO, "chunk_len=%d", chunk_len); if (0 == chunk_len) { DPRINTF("data done\n"); ret = DPL_SUCCESS; goto end; } mode = MODE_CHUNK; chunk_off = 0; if (conn->read_buf_pos < conn->cc) { chunk_remain = MIN(conn->cc - conn->read_buf_pos, chunk_len); ret2 = buffer_func(cb_arg, conn->read_buf + conn->read_buf_pos, chunk_remain); if (DPL_SUCCESS != ret2) { DPL_TRACE(conn->ctx, DPL_TRACE_ERR, "buffer_func"); ret = DPL_FAILURE; goto end; } conn->read_buf_pos += chunk_remain; chunk_off += chunk_remain; } break ; default: assert(0); } free(line); line = NULL; } } end: if (NULL != line) free(line); if (DPL_SUCCESS == ret) { if (NULL != http_statusp) *http_statusp = http_reply.code; } return ret; }