/* Parse a header and fill in any relevant fields in the response structure. */ int http_response_parse_header(struct http_response *response, const char *header) { int code; code = http_parse_header(&response->header, header); if (code != 0) return code; code = http_header_get_content_length(response->header, &response->content_length); if (code != 0) return code; return 0; }
/** * @return * -1 if a header was invalid (see http status for details) * 0 if all headers are successfully handled (end-of-header reached) */ int http_process_headers(http_t *ctx, char *buf, size_t buf_size) { RUNTIME_ASSERT(ctx); RUNTIME_ASSERT(HTTP_STATE_HEADERS == ctx->state); for (;;) { char *name, *value; name = value = NULL; switch (http_parse_header(ctx, buf, buf_size, &name, &value)) { case -1: DBUG("http_parse_header() failed: %u \"%s\"", ctx->status_code, ctx->status_msg); return -1; case 0: RUNTIME_ASSERT(HTTP_STATE_BODY == ctx->state); return 0; case 1: break; default: RUNTIME_ASSERT(0); http_set_status(ctx, 500, "Internal Server Error"); return -1; } RUNTIME_ASSERT(HTTP_STATE_HEADERS == ctx->state); RUNTIME_ASSERT(name); RUNTIME_ASSERT(value); #if 0 http_log(ctx, "name=\"%s\"; value=\"%s\"", name, value); #endif if (0 != http_handle_header(ctx, name, value)) break; } return -1; }
int http_parse(struct request_t *self, char *data, int len) { char *p; /* get request line */ p = http_parse_request(self, data, len); if (p == NULL) { return -1; } len -= p - data; data = p; /* get other headers until end of the request */ while ((len > 0) && !((data[0] == '\n') || (len >= 2 && data[0] == '\r' && data[1] == '\n'))) { p = http_parse_header(self, data, len); if (p == NULL) { return -1; } len -= p - data; data = p; } return 0; }
int http_parse(int fd, struct http_request *r) { int recvd; static char command[HTTP_BUFFER_LEN + 1]; char *i; int newline_machine = 0; char *linestart; char *bodystart; static char linebuf[HTTP_LINE_LEN + 1]; int linenum; if ((recvd = read(fd, (void*)command, HTTP_BUFFER_LEN)) < 0) { if (errno == EAGAIN) { printf("Eagain\n"); return recvd; } perror("recvfrom"); exit(1); } if ((recvd == 1 && *((char*)command) == '\0') || (recvd == 0)) { return 0; } command[HTTP_BUFFER_LEN] = '\0'; linenum = 0; linestart = command; for (i = command; *i; ++i) { switch (newline_machine) { case 0: case 2: { if (*i == '\r') newline_machine++; else newline_machine = 0; } break; case 1: { if (*i == '\n') newline_machine++; else newline_machine = 0; } break; case 3: { if (*i == '\n') newline_machine++; else newline_machine = 0; } break; default: { newline_machine = 0; } } if (newline_machine == 2) { int linelength = i - linestart; linelength = linelength < HTTP_LINE_LEN ? linelength : HTTP_LINE_LEN; strncpy(linebuf, linestart, i - linestart); linebuf[HTTP_LINE_LEN] = '\0'; if (linenum == 0) { if (http_parse_status(r, linebuf) < 0) { printf("Estatus\n"); return -1; } } else { if (http_parse_header(r, linebuf) < 0) { printf("Eheader\n"); return -1; } } linestart = i + 1; linenum++; } if (newline_machine == 4) { bodystart = i + 1; if (http_parse_body(r, bodystart) < 0) { printf("Ebody\n"); return -1; } linenum++; break; } } return 0; }
/* Return a usable socket descriptor after proxy negotiation, or -1 on any error. If any bytes are received through the proxy after negotiation, they are written to stdout. */ static int do_proxy_http(void) { struct socket_buffer sockbuf; char *request; char *status_line, *header; char *remainder; size_t len; int sd, code; int n; sd = do_connect(SOCK_STREAM); if (sd == -1) { loguser("Proxy connection failed: %s.\n", socket_strerror(socket_errno())); return -1; } status_line = NULL; header = NULL; /* First try a request with no authentication. */ request = http_connect_request(&httpconnect, &n); if (send(sd, request, n, 0) < 0) { loguser("Error sending proxy request: %s.\n", socket_strerror(socket_errno())); free(request); return -1; } free(request); socket_buffer_init(&sockbuf, sd); if (http_read_status_line(&sockbuf, &status_line) != 0) { loguser("Error reading proxy response Status-Line.\n"); goto bail; } code = http_parse_status_line_code(status_line); logdebug("Proxy returned status code %d.\n", code); free(status_line); status_line = NULL; if (http_read_header(&sockbuf, &header) != 0) { loguser("Error reading proxy response header.\n"); goto bail; } if (code == 407 && o.proxy_auth != NULL) { struct http_header *h; struct http_challenge challenge; close(sd); sd = -1; if (http_parse_header(&h, header) != 0) { loguser("Error parsing proxy response header.\n"); goto bail; } free(header); header = NULL; if (http_header_get_proxy_challenge(h, &challenge) == NULL) { loguser("Error getting Proxy-Authenticate challenge.\n"); http_header_free(h); goto bail; } http_header_free(h); sd = do_connect(SOCK_STREAM); if (sd == -1) { loguser("Proxy reconnection failed: %s.\n", socket_strerror(socket_errno())); goto bail; } request = http_connect_request_auth(&httpconnect, &n, &challenge); if (request == NULL) { loguser("Error building Proxy-Authorization header.\n"); http_challenge_free(&challenge); goto bail; } logdebug("Reconnection header:\n%s", request); if (send(sd, request, n, 0) < 0) { loguser("Error sending proxy request: %s.\n", socket_strerror(socket_errno())); free(request); http_challenge_free(&challenge); goto bail; } free(request); http_challenge_free(&challenge); socket_buffer_init(&sockbuf, sd); if (http_read_status_line(&sockbuf, &status_line) != 0) { loguser("Error reading proxy response Status-Line.\n"); goto bail; } code = http_parse_status_line_code(status_line); logdebug("Proxy returned status code %d.\n", code); free(status_line); status_line = NULL; if (http_read_header(&sockbuf, &header) != 0) { loguser("Error reading proxy response header.\n"); goto bail; } } free(header); header = NULL; if (code != 200) { loguser("Proxy returned status code %d.\n", code); return -1; } remainder = socket_buffer_remainder(&sockbuf, &len); Write(STDOUT_FILENO, remainder, len); return sd; bail: if (sd != -1) close(sd); if (status_line != NULL) free(status_line); if (header != NULL) free(header); return -1; }
static void on_read(void *arg) { module_data_t *mod = arg; asc_timer_destroy(mod->timeout_timer); mod->timeout_timer = NULL; char *buffer = mod->buffer; int skip = mod->ts_len_in_buf; int r = asc_socket_recv(mod->sock, buffer + skip, HTTP_BUFFER_SIZE - skip); if(r <= 0) { on_close(mod); return; } r += mod->ts_len_in_buf;// Imagine that we've received more (+ previous part) int response = 0; parse_match_t m[4]; // parse response if(mod->ready_state == 0) { if(!http_parse_response(buffer, m)) { call_error(mod, "invalid response"); on_close(mod); return; } lua_newtable(lua); response = lua_gettop(lua); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->__lua.oref); lua_pushvalue(lua, -2); // duplicate table lua_setfield(lua, -2, __response); lua_pop(lua, 1); // options lua_pushnumber(lua, atoi(&buffer[m[2].so])); lua_setfield(lua, response, __code); lua_pushlstring(lua, &buffer[m[3].so], m[3].eo - m[3].so); lua_setfield(lua, response, __message); skip = m[0].eo; mod->ready_state = 1; if(skip >= r) { lua_pop(lua, 1); // response return; } } // parse headers if(mod->ready_state == 1) { if(!response) { lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->__lua.oref); lua_getfield(lua, -1, __response); lua_remove(lua, -2); response = lua_gettop(lua); } int headers_count = 0; lua_getfield(lua, response, __headers); if(lua_isnil(lua, -1)) { lua_pop(lua, 1); lua_newtable(lua); lua_pushvalue(lua, -1); lua_setfield(lua, response, __headers); } else { headers_count = luaL_len(lua, -1); } const int headers = lua_gettop(lua); while(skip < r && http_parse_header(&buffer[skip], m)) { const size_t so = m[1].so; const size_t length = m[1].eo - so; if(!length) { skip += m[0].eo; mod->ready_state = 2; break; } const char *header = &buffer[skip + so]; if(!strncasecmp(header, __transfer_encoding, sizeof(__transfer_encoding) - 1)) { const char *val = &header[sizeof(__transfer_encoding) - 1]; if(!strncasecmp(val, __chunked, sizeof(__chunked) - 1)) mod->is_chunked = 1; } else if(!strncasecmp(header, __connection, sizeof(__connection) - 1)) { const char *val = &header[sizeof(__connection) - 1]; if(!strncasecmp(val, __close, sizeof(__close) - 1)) mod->is_close = 1; else if(!strncasecmp(val, __keep_alive, sizeof(__keep_alive) - 1)) mod->is_keep_alive = 1; } else if(!strncasecmp(header, __content_length, sizeof(__content_length) - 1)) { const char *val = &header[sizeof(__content_length) - 1]; mod->is_content_length = 1; mod->chunk_left = strtoul(val, NULL, 10); } ++headers_count; lua_pushnumber(lua, headers_count); lua_pushlstring(lua, header, length); lua_settable(lua, headers); skip += m[0].eo; } lua_pop(lua, 1); // headers if(mod->ready_state == 2) { get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); lua_pushvalue(lua, response); lua_call(lua, 2, 0); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->__lua.oref); lua_pushnil(lua); lua_setfield(lua, -2, __response); lua_pop(lua, 1); // options } lua_pop(lua, 1); // response if(skip >= r) return; } // content if(mod->ready_state == 2) { /* Push to stream */ if (mod->is_ts) { int pos = skip - mod->ts_len_in_buf;// buffer rewind while (r - pos >= TS_PACKET_SIZE) { module_stream_send(mod, (uint8_t*)&mod->buffer[pos]); pos += TS_PACKET_SIZE; } int left = r - pos; if (left > 0) {//there is something usefull in the end of buffer, move it to begin if (pos > 0) memmove(&mod->buffer[0], &mod->buffer[pos], left); mod->ts_len_in_buf = left; } else {//all data is processed mod->ts_len_in_buf = 0; } } // Transfer-Encoding: chunked else if(mod->is_chunked) { while(skip < r) { if(!mod->chunk_left) { if(!http_parse_chunk(&buffer[skip], m)) { call_error(mod, "invalid chunk"); on_close(mod); return; } char cs_str[] = "00000000"; const size_t cs_size = m[1].eo - m[1].so; const size_t cs_skip = 8 - cs_size; memcpy(&cs_str[cs_skip], &buffer[skip], cs_size); uint8_t cs_hex[4]; str_to_hex(cs_str, cs_hex, sizeof(cs_hex)); mod->chunk_left = (cs_hex[0] << 24) | (cs_hex[1] << 16) | (cs_hex[2] << 8) | (cs_hex[3] ); skip += m[0].eo; if(!mod->chunk_left) { if(mod->is_keep_alive) { // keep-alive connection get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); lua_pushstring(lua, ""); lua_call(lua, 2, 0); } else { // close connection on_close(mod); } return; } } const size_t r_skip = r - skip; get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); if(mod->chunk_left < r_skip) { lua_pushlstring(lua, &buffer[skip], mod->chunk_left); lua_call(lua, 2, 0); skip += mod->chunk_left; mod->chunk_left = 0; if(buffer[skip] == '\r') ++skip; if(buffer[skip] == '\n') ++skip; else { call_error(mod, "invalid chunk"); on_close(mod); return; } } else { lua_pushlstring(lua, &buffer[skip], r_skip); lua_call(lua, 2, 0); mod->chunk_left -= r_skip; break; } } } // Content-Length else if(mod->is_content_length) { if(mod->chunk_left > 0) { const size_t r_skip = r - skip; get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); if(mod->chunk_left > r_skip) { lua_pushlstring(lua, &buffer[skip], r_skip); lua_call(lua, 2, 0); mod->chunk_left -= r_skip; } else { lua_pushlstring(lua, &buffer[skip], mod->chunk_left); lua_call(lua, 2, 0); mod->chunk_left = 0; if(mod->is_keep_alive) { // keep-alive connection get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); lua_pushstring(lua, ""); lua_call(lua, 2, 0); } else { // close connection on_close(mod); } return; } } } // Stream else { get_lua_callback(mod); lua_rawgeti(lua, LUA_REGISTRYINDEX, mod->idx_self); lua_pushlstring(lua, &buffer[skip], r - skip); lua_call(lua, 2, 0); } } } /* on_read */
// Processes a single request from a web client. void webserver_process_request (int connfd, string clientaddress) { mutex_requests.lock (); config_globals_simultaneous_connection_count++; mutex_requests.unlock (); // The environment for this request. // It gets passed around from function to function during the entire request. // This provides thread-safety to the request. Webserver_Request request; // Store remote client address in the request. request.remote_address = clientaddress; try { if (config_globals_running) { // Connection health flag. bool connection_healthy = true; // Read the client's request. // With the HTTP protocol it is not possible to read the request till EOF, // because EOF does never come, because the browser keeps the connection open // for the response. // The HTTP protocol works per line. // Read one line of data from the client. // An empty line marks the end of the headers. #define BUFFERSIZE 2048 int bytes_read; bool header_parsed = true; char buffer [BUFFERSIZE]; // Fix valgrind unitialized value message. memset (&buffer, 0, BUFFERSIZE); do { bytes_read = get_line (connfd, buffer, BUFFERSIZE); if (bytes_read <= 0) connection_healthy = false; // Parse the browser's request's headers. header_parsed = http_parse_header (buffer, &request); } while (header_parsed); if (connection_healthy) { // In the case of a POST request, more data follows: The POST request itself. // The length of that data is indicated in the header's Content-Length line. // Read that data, and parse it. string postdata; if (request.is_post) { bool done_reading = false; int total_bytes_read = 0; do { bytes_read = read (connfd, buffer, BUFFERSIZE); for (int i = 0; i < bytes_read; i++) { postdata += buffer [i]; } // EOF indicates reading is ready. // An error also indicates that reading is ready. if (bytes_read <= 0) done_reading = true; if (bytes_read < 0) connection_healthy = false; // "Content-Length" bytes read: Done. total_bytes_read += bytes_read; if (total_bytes_read >= request.content_length) done_reading = true; } while (!done_reading); if (total_bytes_read < request.content_length) connection_healthy = false; } if (connection_healthy) { http_parse_post (postdata, &request); // Assemble response. bootstrap_index (&request); http_assemble_response (&request); // Send response to browser. const char * output = request.reply.c_str(); // The C function strlen () fails on null characters in the reply, so take string::size() size_t length = request.reply.size (); int written = write (connfd, output, length); if (written) {}; } else { // cerr << "Insufficient data received, closing connection" << endl; } } else { // cerr << "Unhealthy connection was closed" << endl; } } } catch (exception & e) { string message ("Internal error: "); message.append (e.what ()); Database_Logs::log (message); } catch (exception * e) { string message ("Internal error: "); message.append (e->what ()); Database_Logs::log (message); } catch (...) { Database_Logs::log ("A general internal error occurred"); } // Done: Close. close (connfd); mutex_requests.lock (); config_globals_simultaneous_connection_count--; mutex_requests.unlock (); }
/* called when a web connection becomes readable */ static void websrv_recv(struct stream_connection *conn, uint16_t flags) { struct web_server_data *wdata; struct websrv_context *web = talloc_get_type(conn->private_data, struct websrv_context); NTSTATUS status; uint8_t buf[1024]; size_t nread; uint8_t *p; DATA_BLOB b; /* not the most efficient http parser ever, but good enough for us */ status = socket_recv(conn->socket, buf, sizeof(buf), &nread); if (NT_STATUS_IS_ERR(status)) goto failed; if (!NT_STATUS_IS_OK(status)) return; if (!data_blob_append(web, &web->input.partial, buf, nread)) goto failed; /* parse any lines that are available */ b = web->input.partial; while (!web->input.end_of_headers && (p=(uint8_t *)memchr(b.data, '\n', b.length))) { const char *line = (const char *)b.data; *p = 0; if (p != b.data && p[-1] == '\r') { p[-1] = 0; } status = http_parse_header(web, line); if (!NT_STATUS_IS_OK(status)) return; b.length -= (p - b.data) + 1; b.data = p+1; } /* keep any remaining bytes in web->input.partial */ if (b.length == 0) { b.data = NULL; } b = data_blob_talloc(web, b.data, b.length); data_blob_free(&web->input.partial); web->input.partial = b; /* we finish when we have both the full headers (terminated by a blank line) and any post data, as indicated by the content_length */ if (web->input.end_of_headers && web->input.partial.length >= web->input.content_length) { if (web->input.partial.length > web->input.content_length) { web->input.partial.data[web->input.content_length] = 0; } EVENT_FD_NOT_READABLE(web->conn->event.fde); /* the reference/unlink code here is quite subtle. It is needed because the rendering of the web-pages, and in particular the esp/ejs backend, is semi-async. So we could well end up in the connection timeout code while inside http_process_input(), but we must not destroy the stack variables being used by that rendering process when we handle the timeout. */ if (!talloc_reference(web->task, web)) goto failed; wdata = talloc_get_type(web->task->private_data, struct web_server_data); if (wdata == NULL) goto failed; wdata->http_process_input(wdata, web); talloc_unlink(web->task, web); } return; failed: stream_terminate_connection(conn, "websrv_recv: failed"); }
/* parsing lists {{{*/ if(service) { xmlNodePtr memberships = findNode(service->children, "Memberships", 1); xmlNodePtr ms; xmlNodePtr role; xmlNodePtr members, member; xmlNodePtr pname; xmlNodePtr type; xmlNodePtr lastchange; xmlChar *content; int flag = 0; lastchange = findNode(service->children, "LastChange", 1); content = xmlNodeGetContent(lastchange); cl->lastchange = strdup((char*)content); DMSG(stderr, "Contact: lastchange = %s\n", cl->lastchange); if(!memberships) { fprintf(stderr, "NULL membership\n"); count = 0; goto cleanup; } for(ms=memberships->children;ms;ms=ms->next) { int ctype = 1; if(!ms->children) continue; role = findNode(ms->children, "MemberRole", 1); if(!role) { fprintf(stderr, "Null role\n"); count = 0; goto cleanup; } members = findNode(role, "Members", 1); if(!members) continue; if(xmlStrEqual(role->children->content, (xmlChar*)"Allow")) flag = 3; else if(xmlStrEqual(role->children->content, (xmlChar*)"Block")) flag = 4; else continue; for(member=members->children;member;member=member->next) { Contact *c; type = findNode(member->children, "Type", 1); content = xmlNodeGetContent(type); if(!content) { fprintf(stderr, "NULL Type\n"); continue; } if(xmlStrEqual(content, (xmlChar*)"Passport")) { pname = findNode(member->children, "PassportName", 1); ctype = 1; } else if(xmlStrEqual(content, (xmlChar*)"Email")) { pname = findNode(member->children, "Email", 1); ctype = 32; } else continue; xmlFree(content); if(!pname) { fprintf(stderr, "NULL PassportName or Email\n"); continue; } content = xmlNodeGetContent(pname); if(content) { char name[32]; char domain[32]; if(sscanf((char*)content, "%[^@]@%s", name, domain) != 2) { fprintf(stderr, "parse contact: malformed email: %s\n", content); continue; } c = contact_new((char*)content); c->name = strdup(name); c->type = ctype; c->status = NA; c->inlist |= flag; c->domain = NULL; /* should be filled during sort */ cl_append_contact(cl, c, name, domain); xmlFree(content); count++; } } } }/*}}}*/ DMSG(stderr, "parsed contact count: %d\n", count); cleanup: cl->flag &= ~CL_INITLIST; return count; }/*}}}*/ int _cl_do_soapreq_ab(CL *cl)/*{{{*/ { TCPClient *client; char *req = NULL; char *header; char buf[512]; int ret, len; char *ptr = NULL; client = tcpclient_new("contacts.msn.com", 80); ret = _cl_load_soapreq_ab(cl, cl->ablastchange, &req, TRUE); if(ret) { tcpclient_connect(client); header = (char*)xmalloc(strlen(ab_request_header) + 32); DMSG(stderr, "sending ab request\n"); len = sprintf(header, "%s%d\r\n\r\n", ab_request_header, ret); if(tcpclient_send(client, header, len) <= 0) goto cleanup; if(tcpclient_send(client, req, ret) <= 0) goto cleanup; len = tcpclient_recv_header(client, &ptr); /* header */ if(ptr) { HTTPHeader *header; xmlDocPtr doc; xmlParserCtxtPtr ctxt; FILE *fp; DMSG(stderr, "AB response header:\n%s", ptr); header = http_parse_header(ptr); len = header->content_length; DMSG(stderr, "Length: %d\n", len); http_header_destroy(header); memset(buf, 0, sizeof(buf)); fp = fopen("addressbook.xml", "w"); fprintf(fp, buf); len -= (ret = tcpclient_recv(client, buf, sizeof(buf)-1)); ctxt = xmlCreatePushParserCtxt(NULL, NULL, buf, ret, "addressbook.xml"); fprintf(fp, buf); if(ctxt == NULL) { fprintf(stderr, "failed to create parser context"); return 0; } while(len > 0) { memset(buf, 0, sizeof(buf)); len -= (ret=tcpclient_recv(client, buf, sizeof(buf)-1)); fprintf(fp, buf); xmlParseChunk(ctxt, buf, ret, 0); } fclose(fp); xmlParseChunk(ctxt, buf, 0, 1); tcpclient_destroy(client); client = NULL; doc = ctxt->myDoc; len = ctxt->wellFormed; xmlFreeParserCtxt(ctxt); //count += _cl_parse_contacts(cl, doc); xmlFreeDoc(doc); xmlCleanupParser(); DMSG(stderr, "addressbook xml parsing done: %s\n", len?"good":"malformed"); xfree(ptr); } else { DMSG(stderr, "ab: no header found\n\r"); } } else { fprintf(stderr, "failed to load abreq\n"); } cleanup: xfree(header); return 0; }/*}}}*/ int cl_load_contacts(CL *cl, const char* file)/*{{{*/ { int ret; xmlDocPtr doc; xmlNodePtr root; xmlNodePtr contact; xmlNodePtr node; xmlChar *content; doc = xmlReadFile(file, NULL, 0); if (doc == NULL) { fprintf(stderr, "Failed to parse %s\n", file); return 0; } ret = 0; root = xmlDocGetRootElement(doc); contact = findNode(root->children, "contact", 3); #define READSTR(dst,elem) node = findNode(contact->children, elem, 1); \ content = xmlNodeGetContent(node); \ dst = strdup((char*)content); \ xmlFree(content) #define READINT(dst, elem) node = findNode(contact->children, elem, 1); \ content = xmlNodeGetContent(node); \ dst = atoi((char*)content); \ xmlFree(content) for(;contact;contact=contact->next) { Contact *c; node = findNode(contact->children, "nick", 1); content = xmlNodeGetContent(node); c = contact_new((char*)content); xmlFree(content); READSTR(c->name, "name"); READSTR(c->PSM, "PSM"); READINT(c->inlist, "inlist"); READINT(c->type, "type"); c->status = NA; node = findNode(contact->children, "domain", 1); content = xmlNodeGetContent(node); c->domain = NULL; /* should be filled during sort */ cl_append_contact(cl, c, c->name, (char*)content); xmlFree(content); ret++; } node = findNode(root->children, "lastchange", 3); if(node) { content = xmlNodeGetContent(node); cl->lastchange = strdup((char*)content); xmlFree(content); } xmlFreeDoc(doc); return ret; }/*}}}*/ void cl_save(CL *cl, const char *filename)/*{{{*/ { Contact *c; FILE *fp = fopen(filename, "w"); if(!fp) return; fprintf(fp, "<?xml version=\"1.0\" encoding=\"utf-8\"?>"); fprintf(fp, "<contactinfo>"); fprintf(fp, "<contacts>"); for(c=cl->list;c;c=c->g_next) { fprintf(fp, "<contact>"); fprintf(fp, "<name>%s</name>", c->name); fprintf(fp, "<nick>%s</nick>", c->nick); fprintf(fp, "<PSM>%s</PSM>", c->PSM?c->PSM:""); fprintf(fp, "<domain>%s</domain>", c->domain); fprintf(fp, "<inlist>%d</inlist>", c->inlist); fprintf(fp, "<type>%d</type>", c->type); fprintf(fp, "</contact>"); } fprintf(fp, "</contacts>"); if(cl->lastchange) fprintf(fp,"<lastchange>%s</lastchange>", cl->lastchange); if(cl->ablastchange) fprintf(fp,"<ablastchange>%s</ablastchange>", cl->ablastchange); fprintf(fp, "</contactinfo>"); fflush(fp); fclose(fp); }/*}}}*/ int _cl_do_soapreq_ms(CL *cl)/*{{{*/ { SSLClient *client; int ret; int len; int count = 0; char *req = NULL; char *header; char contactfile[64]; FILE *fp; header = (char*)xmalloc(strlen(ms_request_header) + 32); client = sslclient_new(DEFAULTSERVER, 443); if(!sslclient_connect(client)) return 0; /* connected */ MD5((unsigned char*)cl->account->username, strlen(cl->account->username), (unsigned char*)contactfile); sprintf(contactfile, "%x%x.xml", (unsigned char)contactfile[0], (unsigned char)contactfile[1]); if((fp=fopen(contactfile, "r"))) { DMSG(stderr, "loading cached contacts...\n"); if((count = cl_load_contacts(cl, contactfile))) ret = _cl_load_soapreq_ms(cl, cl->lastchange, &req, FALSE); else ret = _cl_load_soapreq_ms(cl, cl->lastchange, &req, TRUE); DMSG(stderr, "%d contacts loaded from cache...\n", count); fclose(fp); } else ret = _cl_load_soapreq_ms(cl, cl->lastchange, &req, TRUE); if(ret) { char buf[512] = {0}; char *ptr = NULL; xmlDocPtr doc; xmlParserCtxtPtr ctxt; FILE *fp; DMSG(stderr, "sending cl request\n"); /* send request */ len = sprintf(header, ms_request_header, ret); if(sslclient_send(client, header, len) <= 0) goto cleanup; if(sslclient_send(client, req, ret) <= 0) goto cleanup; DMSG(stderr, "getting cl response\n"); /* get response */ DMSG(stderr, "HEADER:\n"); len = sslclient_recv_header(client, &ptr); /* header */ if(ptr) { HTTPHeader *header; DMSG(stderr, ptr); header = http_parse_header(ptr); len = header->content_length; DMSG(stderr, "content length: %d\n", len); http_header_destroy(header); xfree(ptr); } else { DMSG(stderr, "no header found\n\r"); } memset(buf, 0, sizeof(buf)); fp = fopen("contacts.xml", "w"); len -= (ret = sslclient_recv(client, buf, sizeof(buf)-1)); ctxt = xmlCreatePushParserCtxt(NULL, NULL, buf, ret, "contacts.xml"); DMSG(stderr, "RESPONSE:\n"); fprintf(fp, buf); if(ctxt == NULL) { fprintf(stderr, "failed to create parser context"); return 0; } while(len > 0) { memset(buf, 0, sizeof(buf)); len -= (ret=sslclient_recv(client, buf, sizeof(buf)-1)); fprintf(fp, buf); xmlParseChunk(ctxt, buf, ret, 0); } fclose(fp); xmlParseChunk(ctxt, buf, 0, 1); sslclient_destroy(client, FALSE); client = NULL; doc = ctxt->myDoc; len = ctxt->wellFormed; xmlFreeParserCtxt(ctxt); count += _cl_parse_contacts(cl, doc); xmlFreeDoc(doc); xmlCleanupParser(); DMSG(stderr, "contact xml parsing done: %s\n", len?"good":"malformed"); } _cl_sort_contacts(cl); cl_save(cl, contactfile); cleanup: xfree(req); xfree(header); return count; }/*}}}*/
/* parsing lists {{{*/ if(service) { xmlNodePtr memberships = findNode(service->children, "Memberships", 1); xmlNodePtr ms; xmlNodePtr role; xmlNodePtr members, member; xmlNodePtr pname; xmlNodePtr type; xmlNodePtr lastchange; xmlChar *content; int flag = 0; lastchange = findNode(service->children, "LastChange", 1); content = xmlNodeGetContent(lastchange); cl->lastchange = strdup((char*)content); DMSG(stderr, "Contact: lastchange = %s\n", cl->lastchange); if(!memberships) { fprintf(stderr, "NULL membership\n"); count = 0; goto cleanup; } for(ms=memberships->children;ms;ms=ms->next) { int ctype = 1; if(!ms->children) continue; role = findNode(ms->children, "MemberRole", 1); if(!role) { fprintf(stderr, "Null role\n"); count = 0; goto cleanup; } members = findNode(role, "Members", 1); if(!members) continue; if(xmlStrEqual(role->children->content, (xmlChar*)"Allow")) flag = 3; else if(xmlStrEqual(role->children->content, (xmlChar*)"Block")) flag = 4; else continue; for(member=members->children;member;member=member->next) { Contact *c; type = findNode(member->children, "Type", 1); content = xmlNodeGetContent(type); if(!content) { fprintf(stderr, "NULL Type\n"); continue; } if(xmlStrEqual(content, (xmlChar*)"Passport")) { pname = findNode(member->children, "PassportName", 1); ctype = 1; } else if(xmlStrEqual(content, (xmlChar*)"Email")) { pname = findNode(member->children, "Email", 1); ctype = 32; } else continue; xmlFree(content); if(!pname) { fprintf(stderr, "NULL PassportName or Email\n"); continue; } content = xmlNodeGetContent(pname); if(content) { char name[32]; char domain[32]; if(sscanf((char*)content, "%[^@]@%s", name, domain) != 2) { fprintf(stderr, "parse contact: malformed email: %s\n", content); continue; } c = contact_new((char*)content); c->name = strdup(name); c->type = ctype; c->status = NA; c->inlist |= flag; c->domain = NULL; /* should be filled during sort */ cl_append_contact(cl, c, name, domain); xmlFree(content); count++; } } } }/*}}}*/ DMSG(stderr, "parsed contact count: %d\n", count); cleanup: cl->flag &= ~CL_INITLIST; return count; }/*}}}*/ int _cl_do_soapreq_ab(CL *cl)/*{{{*/ { TCPClient *client; char *req = NULL; char *header; char buf[512]; int ret, len; char *ptr = NULL; client = tcpclient_new("contacts.msn.com", 80); ret = _cl_load_soapreq_ab(cl, cl->ablastchange, &req, TRUE); if(ret) { tcpclient_connect(client); header = (char*)xmalloc(strlen(ab_request_header) + 32); DMSG(stderr, "sending ab request\n"); len = sprintf(header, "%s%d\r\n\r\n", ab_request_header, ret); if(tcpclient_send(client, header, len) <= 0) goto cleanup; if(tcpclient_send(client, req, ret) <= 0) goto cleanup; len = tcpclient_recv_header(client, &ptr); /* header */ if(ptr) { HTTPHeader *header; xmlDocPtr doc; xmlParserCtxtPtr ctxt; FILE *fp; DMSG(stderr, "AB response header:\n%s", ptr); header = http_parse_header(ptr); len = header->content_length; DMSG(stderr, "Length: %d\n", len); http_header_destroy(header); memset(buf, 0, sizeof(buf)); fp = fopen("addressbook.xml", "w"); fprintf(fp, buf); len -= (ret = tcpclient_recv(client, buf, sizeof(buf)-1)); ctxt = xmlCreatePushParserCtxt(NULL, NULL, buf, ret, "addressbook.xml"); fprintf(fp, buf); if(ctxt == NULL) { fprintf(stderr, "failed to create parser context"); return 0; } while(len > 0) { memset(buf, 0, sizeof(buf)); len -= (ret=tcpclient_recv(client, buf, sizeof(buf)-1)); fprintf(fp, buf); xmlParseChunk(ctxt, buf, ret, 0); } fclose(fp); xmlParseChunk(ctxt, buf, 0, 1); tcpclient_destroy(client); client = NULL; doc = ctxt->myDoc; len = ctxt->wellFormed; xmlFreeParserCtxt(ctxt); //count += _cl_parse_contacts(cl, doc); xmlFreeDoc(doc); xmlCleanupParser(); DMSG(stderr, "addressbook xml parsing done: %s\n", len?"good":"malformed"); xfree(ptr); } else { DMSG(stderr, "ab: no header found\n\r"); } } else { fprintf(stderr, "failed to load abreq\n"); } cleanup: xfree(header); return 0; }/*}}}*/
guint http_request_read (http_request *h) { gchar *buf = g_new( gchar, BUFSIZ + 1 ); /* GIOStatus r; GError *err = NULL; */ GIOError r; guint s, times, n = 0, t = 0; gchar *c_len_hdr = NULL; guint hdr_len = 0, c_len = 0, tot_req_size = 0; struct timeval tv; fd_set fdset; FD_ZERO(&fdset); FD_SET(g_io_channel_unix_get_fd(h->sock), &fdset); tv.tv_sec = 0; buf[0] = '\0'; buf[BUFSIZ] = '\0'; // for (t = 0, n = BUF_SIZ; n == BUF_SIZ && // h->buffer->len < MAX_REQUEST_SIZE; t += n ) { // BPsmythe: The above (original) loop will never execute // more than once unless the size of the buffer read in (n) // is equal to the constant BUF_SIZE. What is desired is // to keep looping until there is nothing left to read. // The for was changed to look for the end of the headers. // FIXME: We should use the newer g_io_channel_read_char // // TJaqua: Added buffer overflow checking, content read loop from 0.93pre2, and fixed up the timeouts, logging and error exits if (CONFd("Verbosity") >= 7) g_message("http_request_read: READING request from peer %s (on %s, fd: %d)", h->peer_ip, h->sock_ip, g_io_channel_unix_get_fd(h->sock)); if (CONFd("Verbosity") >= 9) g_message("http_request_read: entering HEADER read loop (BUFSIZE=%u)", BUFSIZ); for (times=MAX_REQ_TIMEOUTS; !hdr_len && (times > 0); t += n ) { n=0; /* r = g_io_channel_read_chars( h->sock, buf, BUFSIZ, &n, &err ); if (r == G_IO_STATUS_ERROR || err != NULL) { g_message( "http_request_read: Socket IO ERROR: %s, exiting!", err->message ); g_error_free(err); */ r = g_io_channel_read( h->sock, buf, BUFSIZ, &n); if (r != G_IO_ERROR_NONE) { g_warning( "http_request_read: Socket IO ERROR: %m, exiting!" ); g_free(buf); return 0; } if (CONFd("Verbosity") >= 9) g_message("http_request_read: HEADER loop read %u bytes", n); buf[n] = '\0'; if (n && CONFd("Verbosity") >= 11) syslog_message("RAW_HDR_BUF: ", buf, n); if(strlen(buf) < n-1) g_warning("http_request_read: Trailing data past string in buffer was DICARDED!"); if (h->buffer->len == MAX_REQUEST_SIZE) g_warning("http_request_read: header buffer full (%u bytes, %u bytes discarded!)", MAX_REQUEST_SIZE, n); else if (n <= (MAX_REQUEST_SIZE - h->buffer->len)) { if(CONFd("Verbosity") >= 11) g_message("http_request_read: APPENDING buffer to HEADER."); if(n) g_string_append(h->buffer, buf); else if (CONFd("Verbosity") >= 6) g_message("http_request_read: No data in buffer."); //if(CONFd("Verbosity") >= 11) g_message("http_request_read: Partial HEADER (%u bytes) is: %s", h->buffer->len, h->buffer->str); } else { if(CONFd("Verbosity") >= 6) g_warning("http_request_read: header buffer full (%u bytes, %u bytes discarded!)", MAX_REQUEST_SIZE, n - (MAX_REQUEST_SIZE - h->buffer->len)); buf[MAX_REQUEST_SIZE - h->buffer->len] = '\0'; g_string_append(h->buffer, buf); } times--; // BPsmythe: Check for the end of the headers. if (hdr_len = http_get_hdr_len(h->buffer->str)) { if (CONFd("Verbosity") >= 6) g_message("http_request_read: HEADER END found, length: %u", hdr_len ); } else { if(!times) { if(CONFd("Verbosity") >= 6) { g_message("http_request_read: ERROR: HEADER END not found after %d tries, exiting!", MAX_REQ_TIMEOUTS); if (!t) g_message("http_request_read: Empty HTTP-request header."); else g_message("http_request_read: Invalid HTTP-request header, %u bytes read.", t+n); } //Should I send a FIN packet to shutdown the socket? g_free(buf); return 0; } if(CONFd("Verbosity") >= 11) g_message("http_request_read: Waiting for next I/O on socket, (%d more tries).", times); tv.tv_usec = REQ_TIMEOUT; while(times && !(s = select (g_io_channel_unix_get_fd(h->sock)+1, &fdset, NULL, NULL, &tv))) { times--; if (CONFd("Verbosity") >= 7) g_message("http_request_read: HEADER select timeout, %d more tries", times); tv.tv_usec = REQ_TIMEOUT; } if(s<0) { g_warning("http_request_read: ERROR in select, exiting!"); g_free(buf); return 0; } else if(!times) { if(CONFd("Verbosity") >= 6) { g_message("http_request_read: ERROR: Too many TIMEOUTS waiting for HEADER end!"); if (!t) g_message("http_request_read: Empty HTTP-request header."); else g_message("http_request_read: Invalid HTTP-request header, %u bytes read.", t+n); } //Should I send a FIN packet to shutdown the socket? g_free(buf); return 0; } else if(CONFd("Verbosity") >= 11) g_message("http_request_read: Recieved I/O on socket."); } } if (CONFd("Verbosity") >= 10) syslog_message("RAW_HEADER: ", h->buffer->str, h->buffer->len); // Read the content length from the header http_parse_header( h, h->buffer->str ); if( (HEADER("Content-length")) && (c_len = atoi(HEADER("Content-length"))) ) { if (CONFd("Verbosity") >= 9) g_message("http_request_read: entering CONTENT read loop to read %u bytes.", c_len); tot_req_size = hdr_len + c_len; for (times=MAX_REQ_TIMEOUTS; (t < tot_req_size) && (times > 0); t += n ) { if (CONFd("Verbosity") >= 9) g_message("http_request_read: %u bytes of %u total.", t, tot_req_size ); n=0; /* r = g_io_channel_read_chars( h->sock, buf, BUFSIZ, &n, &err ); if (r == G_IO_STATUS_ERROR || err != NULL) { g_message( "http_request_read: Socket-IO ERROR: %s, exiting!", err->message ); g_error_free(err); */ r = g_io_channel_read( h->sock, buf, BUFSIZ, &n); if (r != G_IO_ERROR_NONE) { g_warning( "http_request_read: Socket-IO ERROR: %m, exiting!" ); g_free(buf); return 0; } if (CONFd("Verbosity") >= 9) g_message("http_request_read: CONTENT loop read %d bytes", n ); buf[n] = '\0'; if (n && CONFd("Verbosity") >= 11) syslog_message("RAW_CON_BUF: ", buf, n); if (h->buffer->len == MAX_REQUEST_SIZE) { if(CONFd("Verbosity") >= 6) g_warning("http_request_read: Maximum request length EXCEEDED (%u bytes discarded! Continuing to read out content.)", n); } else if (h->buffer->len == tot_req_size) { if(CONFd("Verbosity") >= 6) g_warning("http_request_read: Content length EXCEEDED (%u bytes discarded! Shouldn't happen!)", n); } else if (h->buffer->len + n >= MAX_REQUEST_SIZE) { if(CONFd("Verbosity") >= 6) g_warning("http_request_read: Max buffer length EXCEEDED (%u bytes discarded! Continuing to read out content.)", n - (MAX_REQUEST_SIZE - h->buffer->len)); buf[MAX_REQUEST_SIZE - h->buffer->len] = '\0'; g_string_append(h->buffer, buf); } else if (n <= (tot_req_size - h->buffer->len)) { if(CONFd("Verbosity") >= 11) g_message("http_request_read: APPENDING buffer to CONTENT."); if(n) g_string_append(h->buffer, buf); else if (CONFd("Verbosity") >= 6) g_message("http_request_read: No data in buffer."); } else { if(CONFd("Verbosity") >= 6) g_warning("http_request_read: Content length EXCEEDED (%u bytes added, %u bytes discarded!)", tot_req_size - h->buffer->len, n - (tot_req_size - h->buffer->len)); buf[tot_req_size - h->buffer->len] = '\0'; g_string_append(h->buffer, buf); } times--; // TJaqua: Check for the end of the content. if ((t+n) >= tot_req_size) { if (CONFd("Verbosity") >= 6) g_message("http_request_read: CONTENT end reached, length: %u", tot_req_size); } else { if (!times) { if(CONFd("Verbosity") >= 6) { g_message("http_request_read: ERROR: CONTENT END not found after %d tries, exiting!", MAX_REQ_TIMEOUTS); if (t == hdr_len) g_message("http_request_read: Empty CONTENT, socket may have stalled."); else g_message("http_request_read: CONTENT unfinished, %u bytes read.", t+n); } //Should I send a FIN packet to shutdown the socket? g_free(buf); //We still got the header, though, so return it. g_string_truncate(h->buffer, hdr_len); return hdr_len; } if(CONFd("Verbosity") >= 11) g_message("http_request_read: Waiting for next I/O on socket."); tv.tv_usec = REQ_TIMEOUT; while (times && !(s = select (g_io_channel_unix_get_fd(h->sock)+1, &fdset, NULL, NULL, &tv))) { times--; if (CONFd("Verbosity") >= 7) g_message("http_request_read: CONTENT select timeout, %d more tries", times); tv.tv_usec = REQ_TIMEOUT; } if(s<0) { g_warning("http_request_read: ERROR in select, exiting!"); g_free(buf); //We still got the header, though, so return it. g_string_truncate(h->buffer, hdr_len); return hdr_len; } else if (!times) { if(CONFd("Verbosity") >= 6) { g_message("http_request_read: ERROR: Too many TIMEOUTS waiting for CONTENT end!"); if (t == hdr_len) g_message("http_request_read: Empty CONTENT, socket may have stalled."); else g_message("http_request_read: Invalid HTTP-request header, %u bytes read.", t+n); } //Should I send a FIN packet to shutdown the socket? g_free(buf); //We still got the header, though, so return it. g_string_truncate(h->buffer, hdr_len); return hdr_len; } else if (CONFd("Verbosity") >= 11) g_message("http_request_read: Received I/O on socket."); } } if (CONFd("Verbosity") >= 10) syslog_message("RAW_CONTENT: ", &(h->buffer->str[hdr_len]), h->buffer->len - hdr_len); if (t<tot_req_size) g_message("http_request_read: CONTENT unfinished - should not happen!"); } if (CONFd("Verbosity") >= 6) g_message("http_request_read: FINISHED read (%u bytes total), exiting.", t); g_free(buf); return t; }