int send_response(struct http_response *resp) { struct MHD_Response *response; struct http_header *hdr; char *origin; int ret; response = MHD_create_response_from_data(resp->ndata, (void *)resp->data, MHD_NO, MHD_YES); assert(response); for (hdr = resp->headers; hdr; hdr = hdr->next) MHD_add_response_header(response, hdr->key, hdr->value); MHD_add_response_header(response, "Access-Control-Allow-Headers", "Authorization, Origin"); MHD_add_response_header(response, "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); origin = http_get_header(resp->connection, "Origin"); MHD_add_response_header(response, "Access-Control-Allow-Origin", origin ? origin : "*"); free(origin); ret = MHD_queue_response(resp->connection, resp->status, response); MHD_destroy_response(response); return (ret); }
static int check_auth(struct MHD_Connection *connection, struct agent_core_t *core, struct connection_info_struct *con_info) { char passwd[1024]; char *auth; assert(con_info); if (con_info->authed == 0) { auth = http_get_header(connection, "Authorization"); /* * XXX: Should be stored somewhere... */ base64_encode(BASE64, core->config->userpass, strlen(core->config->userpass), passwd, sizeof(passwd)); if (!auth || strncmp(auth, "Basic ", strlen("Basic ")) || strcmp(auth + strlen("Basic "), passwd)) { send_auth_response(connection); free(auth); return (1); } free(auth); con_info->authed = 1; } return (0); }
void * conn_handler(void * arr) { int client_fd = *((int*)arr); int keep_alive = 1; while (keep_alive) { http_t req; if (http_read(&req,client_fd) == -1) { http_free(&req); break; } const char * rh = http_get_status(&req); char * uri = process_http_header_request(rh); const char * conn_type = http_get_header(&req, "Connection"); if (conn_type) { if (strcasecmp("keep-alive",conn_type)) keep_alive = 0; //free(conn_type); } else { keep_alive = 0; } char * output = NULL; if (uri) { size_t size; const char * body = http_get_body(&req,&size); jsonreq_t request; request.key = NULL; request.value = NULL; parsereq(body,&request); jsonres_t response = process_request(uri,request); generateres(&output,&response,uri); if (request.key) free(request.key); if (request.value) free(request.value); //if (request) free(request); free(uri); } char * ret_str = ""; asprintf(&ret_str,"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: %zu\r\n\r\n",strlen(output)); send(client_fd,ret_str,strlen(ret_str),0); send(client_fd,output,strlen(output),0); if (output) free(output); if (ret_str) free(ret_str); http_free(&req); } free(arr); close(client_fd); return NULL; }
//cgi that adds CORS ( Cross Origin Resource Sharing ) to our server int ICACHE_FLASH_ATTR cgi_cors(http_connection *connData) { http_server_config *config = (http_server_config*)connData->cgi.argument;; if(config==NULL) return HTTPD_CGI_NEXT_RULE; if(!config->enable_cors) return HTTPD_CGI_NEXT_RULE; if(connData->state==HTTPD_STATE_ON_URL){ //save cors headers http_set_save_header(connData,HTTP_ACCESS_CONTROL_REQUEST_HEADERS); http_set_save_header(connData,HTTP_ACCESS_CONTROL_REQUEST_METHOD); return HTTPD_CGI_NEXT_RULE; } if(connData->state==HTTPD_STATE_HEADERS_END){ //SET CORS Allow Origin for every request http_SET_HEADER(connData,HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,"*"); header * allow_headers = http_get_header(connData,HTTP_ACCESS_CONTROL_REQUEST_HEADERS); header * allow_methods = http_get_header(connData,HTTP_ACCESS_CONTROL_REQUEST_METHOD); if(allow_headers!=NULL) http_SET_HEADER(connData,HTTP_ACCESS_CONTROL_ALLOW_HEADERS,allow_headers->value); if(allow_methods!=NULL) http_SET_HEADER(connData,HTTP_ACCESS_CONTROL_ALLOW_METHODS,allow_methods->value); // Browsers will send an OPTIONS pre-flight request when posting data on a cross-domain situation // If that's the case here, we can safely return 200 OK with our CORS headers set if(connData->parser.method==HTTP_OPTIONS) { http_response_OK(connData); return HTTPD_CGI_DONE; } } return HTTPD_CGI_NEXT_RULE; }
int http_get_contlen(h_head_info *info) { char * buff; buff = http_get_header(info,"Content-Length"); if(buff == NULL) return -1; return atoi(buff); }
static int check_auth(struct MHD_Connection *connection, struct agent_core_t *core, struct connection_info_struct *con_info) { _cleanup_free_ char *auth = NULL; char base64pw[1024]; assert(con_info); if (con_info->authed == 0) { auth = http_get_header(connection, "Authorization"); /* * XXX: Should be stored somewhere... */ base64_encode(BASE64, core->config->userpass, strlen(core->config->userpass), base64pw, sizeof(base64pw)); if (!auth || strncmp(auth,"Basic ", strlen("Basic ")) || strcmp(auth + strlen("Basic "), base64pw)) { send_auth_response(connection); return 1; } con_info->authed = 1; } return 0; }
int ICACHE_FLASH_ATTR http_ws_handle_connect(http_connection *c) { NODE_DBG("http_ws_handle_connect c =%p",c); if(c->state == HTTPD_STATE_ON_URL){ http_set_save_header(c,HTTP_ORIGIN); http_set_save_header(c,HTTP_CONNECTION); http_set_save_header(c,HTTP_UPGRADE); http_set_save_header(c,HTTP_SEC_WEBSOCKET_KEY); http_set_save_header(c,HTTP_SEC_WEBSOCKET_PROTOCOL); http_set_save_header(c,HTTP_SEC_WEBSOCKET_VERSION); return HTTP_WS_CGI_MORE; } //wait handshake request complete if(c->state != HTTPD_STATE_BODY_END) return HTTP_WS_CGI_MORE; header * upgrade_header = http_get_header(c,HTTP_UPGRADE); header * connection_header = http_get_header(c,HTTP_CONNECTION); header * origin_header = http_get_header(c,HTTP_ORIGIN); header * key_header = http_get_header(c,HTTP_SEC_WEBSOCKET_KEY); if(upgrade_header==NULL) goto badrequest; if(connection_header==NULL) goto badrequest; if(origin_header==NULL) goto badrequest; if(key_header==NULL) goto badrequest; NODE_DBG("headers ok"); if(os_strcasecmp(upgrade_header->value,"websocket")!=0) goto badrequest; // Following (https://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17) //calculate sha1 of concatenetion key+uuid uint8_t digest[20]; //sha1 is always 20 byte long SHA1_CTX ctx; SHA1_Init(&ctx); SHA1_Update(&ctx,key_header->value,os_strlen(key_header->value)); SHA1_Update(&ctx,ws_uuid,os_strlen(ws_uuid)); SHA1_Final(digest,&ctx); char base64Digest[31]; // Base64encode(base64Digest,(const char*)digest,20); //accept the handshake http_SET_HEADER(c,HTTP_UPGRADE,"WebSocket"); http_SET_HEADER(c,HTTP_CONNECTION,"Upgrade"); http_SET_HEADER(c,HTTP_WEBSOCKET_ACCEPT,base64Digest); http_websocket_HANDSHAKE(c); c->handshake_ok=1; if(client_connected_callback!=NULL) client_connected_callback(c); return HTTP_WS_CGI_MORE; badrequest: http_response_BAD_REQUEST(c); return HTTP_WS_CGI_DONE; }
/* Get the key from URL which is expected to specify a http style scheme. On success R_FP has an open stream to read the data. */ gpg_error_t ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp) { gpg_error_t err; http_session_t session = NULL; http_t http = NULL; int redirects_left = MAX_REDIRECTS; estream_t fp = NULL; char *request_buffer = NULL; err = http_session_new (&session, NULL); if (err) goto leave; http_session_set_log_cb (session, cert_log_cb); *r_fp = NULL; once_more: err = http_open (&http, HTTP_REQ_GET, url, /* httphost */ NULL, /* fixme: AUTH */ NULL, 0, /* fixme: proxy*/ NULL, session, NULL, /*FIXME curl->srvtag*/NULL); if (!err) { fp = http_get_write_ptr (http); /* Avoid caches to get the most recent copy of the key. We set both the Pragma and Cache-Control versions of the header, so we're good with both HTTP 1.0 and 1.1. */ es_fputs ("Pragma: no-cache\r\n" "Cache-Control: no-cache\r\n", fp); http_start_data (http); if (es_ferror (fp)) err = gpg_error_from_syserror (); } if (err) { /* Fixme: After a redirection we show the old host name. */ log_error (_("error connecting to '%s': %s\n"), url, gpg_strerror (err)); goto leave; } /* Wait for the response. */ dirmngr_tick (ctrl); err = http_wait_response (http); if (err) { log_error (_("error reading HTTP response for '%s': %s\n"), url, gpg_strerror (err)); goto leave; } switch (http_get_status_code (http)) { case 200: err = 0; break; /* Success. */ case 301: case 302: case 307: { const char *s = http_get_header (http, "Location"); log_info (_("URL '%s' redirected to '%s' (%u)\n"), url, s?s:"[none]", http_get_status_code (http)); if (s && *s && redirects_left-- ) { xfree (request_buffer); request_buffer = xtrystrdup (s); if (request_buffer) { url = request_buffer; http_close (http, 0); http = NULL; goto once_more; } err = gpg_error_from_syserror (); } else err = gpg_error (GPG_ERR_NO_DATA); log_error (_("too many redirections\n")); } goto leave; default: log_error (_("error accessing '%s': http status %u\n"), url, http_get_status_code (http)); err = gpg_error (GPG_ERR_NO_DATA); goto leave; } fp = http_get_read_ptr (http); if (!fp) { err = gpg_error (GPG_ERR_BUG); goto leave; } /* Return the read stream and close the HTTP context. */ *r_fp = fp; http_close (http, 1); http = NULL; leave: http_close (http, 0); http_session_release (session); xfree (request_buffer); return err; }
//Cgi that check the request has the correct HOST header //Using it we can ensure our server has a domain of our choice int ICACHE_FLASH_ATTR cgi_check_host(http_connection *connData) { http_server_config *config = (http_server_config*)connData->cgi.argument; if(config==NULL) return HTTPD_CGI_NEXT_RULE; if(config->host_domain==NULL) return HTTPD_CGI_NEXT_RULE; if(connData->state==HTTPD_STATE_ON_URL){ http_set_save_header(connData,HTTP_HOST); return HTTPD_CGI_NEXT_RULE; } if(connData->state==HTTPD_STATE_HEADERS_END){ header *hostHeader = http_get_header(connData,HTTP_HOST); if(hostHeader==NULL){ NODE_DBG("Host header not found"); http_response_BAD_REQUEST(connData); return HTTPD_CGI_DONE; } const char * domain = config->host_domain; NODE_DBG("Host header found: %s, domain: %s",hostHeader->value,domain); if(os_strncmp(hostHeader->value,domain,strlen(domain))==0) //compare ignoring http:// and last / { NODE_DBG("Hosts match"); return HTTPD_CGI_NEXT_RULE; } else{ NODE_DBG("Hosts don't match"); if(config->enable_captive){ //to enable a captive portal we should redirect here char * redirectUrl = (char *)os_zalloc(strlen(domain)+9); // domain lenght + http:// + / + \0 os_strcpy(redirectUrl,"http://"); os_strcat(redirectUrl,domain); os_strcat(redirectUrl,"/"); http_response_REDIRECT(connData, redirectUrl); os_free(redirectUrl); } else{ //bad request http_response_BAD_REQUEST(connData); } return HTTPD_CGI_DONE; } } return HTTPD_CGI_NEXT_RULE; }
int main (int argc, char **argv) { int last_argc = -1; gpg_error_t err; int rc; parsed_uri_t uri; uri_tuple_t r; http_t hd; int c; unsigned int my_http_flags = 0; int no_out = 0; int tls_dbg = 0; int no_crl = 0; const char *cafile = NULL; http_session_t session = NULL; unsigned int timeout = 0; gpgrt_init (); log_set_prefix (PGM, GPGRT_LOG_WITH_PREFIX | GPGRT_LOG_WITH_PID); if (argc) { argc--; argv++; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--help")) { fputs ("usage: " PGM " URL\n" "Options:\n" " --verbose print timings etc.\n" " --debug flyswatter\n" " --tls-debug N use TLS debug level N\n" " --cacert FNAME expect CA certificate in file FNAME\n" " --timeout MS timeout for connect in MS\n" " --no-verify do not verify the certificate\n" " --force-tls use HTTP_FLAG_FORCE_TLS\n" " --force-tor use HTTP_FLAG_FORCE_TOR\n" " --no-out do not print the content\n" " --no-crl do not consuilt a CRL\n", stdout); exit (0); } else if (!strcmp (*argv, "--verbose")) { verbose++; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose += 2; debug++; argc--; argv++; } else if (!strcmp (*argv, "--tls-debug")) { argc--; argv++; if (argc) { tls_dbg = atoi (*argv); argc--; argv++; } } else if (!strcmp (*argv, "--cacert")) { argc--; argv++; if (argc) { cafile = *argv; argc--; argv++; } } else if (!strcmp (*argv, "--timeout")) { argc--; argv++; if (argc) { timeout = strtoul (*argv, NULL, 10); argc--; argv++; } } else if (!strcmp (*argv, "--no-verify")) { no_verify = 1; argc--; argv++; } else if (!strcmp (*argv, "--force-tls")) { my_http_flags |= HTTP_FLAG_FORCE_TLS; argc--; argv++; } else if (!strcmp (*argv, "--force-tor")) { my_http_flags |= HTTP_FLAG_FORCE_TOR; argc--; argv++; } else if (!strcmp (*argv, "--no-out")) { no_out = 1; argc--; argv++; } else if (!strcmp (*argv, "--no-crl")) { no_crl = 1; argc--; argv++; } else if (!strncmp (*argv, "--", 2)) { fprintf (stderr, PGM ": unknown option '%s'\n", *argv); exit (1); } } if (argc != 1) { fprintf (stderr, PGM ": no or too many URLS given\n"); exit (1); } if (!cafile) cafile = prepend_srcdir ("tls-ca.pem"); if (verbose) my_http_flags |= HTTP_FLAG_LOG_RESP; if (verbose || debug) http_set_verbose (verbose, debug); /* http.c makes use of the assuan socket wrapper. */ assuan_sock_init (); if ((my_http_flags & HTTP_FLAG_FORCE_TOR)) { enable_dns_tormode (1); if (assuan_sock_set_flag (ASSUAN_INVALID_FD, "tor-mode", 1)) { log_error ("error enabling Tor mode: %s\n", strerror (errno)); log_info ("(is your Libassuan recent enough?)\n"); } } #if HTTP_USE_NTBTLS log_info ("new session.\n"); err = http_session_new (&session, NULL, ((no_crl? HTTP_FLAG_NO_CRL : 0) | HTTP_FLAG_TRUST_DEF), my_http_tls_verify_cb, NULL); if (err) log_error ("http_session_new failed: %s\n", gpg_strerror (err)); ntbtls_set_debug (tls_dbg, NULL, NULL); #elif HTTP_USE_GNUTLS rc = gnutls_global_init (); if (rc) log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc)); http_register_tls_callback (verify_callback); http_register_tls_ca (cafile); err = http_session_new (&session, NULL, ((no_crl? HTTP_FLAG_NO_CRL : 0) | HTTP_FLAG_TRUST_DEF), NULL, NULL); if (err) log_error ("http_session_new failed: %s\n", gpg_strerror (err)); /* rc = gnutls_dh_params_init(&dh_params); */ /* if (rc) */ /* log_error ("gnutls_dh_params_init failed: %s\n", gnutls_strerror (rc)); */ /* read_dh_params ("dh_param.pem"); */ /* rc = gnutls_certificate_set_x509_trust_file */ /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */ /* if (rc) */ /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */ /* gnutls_strerror (rc)); */ /* gnutls_certificate_set_dh_params (certcred, dh_params); */ gnutls_global_set_log_function (my_gnutls_log); if (tls_dbg) gnutls_global_set_log_level (tls_dbg); #else (void)err; (void)tls_dbg; (void)no_crl; #endif /*HTTP_USE_GNUTLS*/ rc = http_parse_uri (&uri, *argv, 1); if (rc) { log_error ("'%s': %s\n", *argv, gpg_strerror (rc)); return 1; } printf ("Scheme: %s\n", uri->scheme); if (uri->opaque) printf ("Value : %s\n", uri->path); else { printf ("Auth : %s\n", uri->auth? uri->auth:"[none]"); printf ("Host : %s\n", uri->host); printf ("Port : %u\n", uri->port); printf ("Path : %s\n", uri->path); for (r = uri->params; r; r = r->next) { printf ("Params: %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } for (r = uri->query; r; r = r->next) { printf ("Query : %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } printf ("Flags :%s%s%s%s\n", uri->is_http? " http":"", uri->opaque? " opaque":"", uri->v6lit? " v6lit":"", uri->onion? " onion":""); printf ("TLS : %s\n", uri->use_tls? "yes": (my_http_flags&HTTP_FLAG_FORCE_TLS)? "forced" : "no"); printf ("Tor : %s\n", (my_http_flags&HTTP_FLAG_FORCE_TOR)? "yes" : "no"); } fflush (stdout); http_release_parsed_uri (uri); uri = NULL; if (session) http_session_set_timeout (session, timeout); rc = http_open_document (NULL, &hd, *argv, NULL, my_http_flags, NULL, session, NULL, NULL); if (rc) { log_error ("can't get '%s': %s\n", *argv, gpg_strerror (rc)); return 1; } log_info ("open_http_document succeeded; status=%u\n", http_get_status_code (hd)); { const char **names; int i; names = http_get_header_names (hd); if (!names) log_fatal ("http_get_header_names failed: %s\n", gpg_strerror (gpg_error_from_syserror ())); for (i = 0; names[i]; i++) printf ("HDR: %s: %s\n", names[i], http_get_header (hd, names[i])); xfree (names); } fflush (stdout); switch (http_get_status_code (hd)) { case 200: case 400: case 401: case 403: case 404: { unsigned long count = 0; while ((c = es_getc (http_get_read_ptr (hd))) != EOF) { count++; if (!no_out) putchar (c); } log_info ("Received bytes: %lu\n", count); } break; case 301: case 302: case 307: log_info ("Redirected to: %s\n", http_get_header (hd, "Location")); break; } http_close (hd, 0); http_session_release (session); #ifdef HTTP_USE_GNUTLS gnutls_global_deinit (); #endif /*HTTP_USE_GNUTLS*/ return 0; }
/* Send an HTTP request. On success returns an estream object at R_FP. HOSTPORTSTR is only used for diagnostics. If HTTPHOST is not NULL it will be used as HTTP "Host" header. If POST_CB is not NULL a post request is used and that callback is called to allow writing the post data. */ static gpg_error_t send_request (ctrl_t ctrl, const char *request, const char *hostportstr, const char *httphost, unsigned int httpflags, gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value, estream_t *r_fp) { gpg_error_t err; http_session_t session = NULL; http_t http = NULL; int redirects_left = MAX_REDIRECTS; estream_t fp = NULL; char *request_buffer = NULL; *r_fp = NULL; err = http_session_new (&session, NULL); if (err) goto leave; http_session_set_log_cb (session, cert_log_cb); once_more: err = http_open (&http, post_cb? HTTP_REQ_POST : HTTP_REQ_GET, request, httphost, /* fixme: AUTH */ NULL, (httpflags | (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0)), ctrl->http_proxy, session, NULL, /*FIXME curl->srvtag*/NULL); if (!err) { fp = http_get_write_ptr (http); /* Avoid caches to get the most recent copy of the key. We set both the Pragma and Cache-Control versions of the header, so we're good with both HTTP 1.0 and 1.1. */ es_fputs ("Pragma: no-cache\r\n" "Cache-Control: no-cache\r\n", fp); if (post_cb) err = post_cb (post_cb_value, http); if (!err) { http_start_data (http); if (es_ferror (fp)) err = gpg_error_from_syserror (); } } if (err) { /* Fixme: After a redirection we show the old host name. */ log_error (_("error connecting to '%s': %s\n"), hostportstr, gpg_strerror (err)); goto leave; } /* Wait for the response. */ dirmngr_tick (ctrl); err = http_wait_response (http); if (err) { log_error (_("error reading HTTP response for '%s': %s\n"), hostportstr, gpg_strerror (err)); goto leave; } if (http_get_tls_info (http, NULL)) { /* Update the httpflags so that a redirect won't fallback to an unencrypted connection. */ httpflags |= HTTP_FLAG_FORCE_TLS; } switch (http_get_status_code (http)) { case 200: err = 0; break; /* Success. */ case 301: case 302: case 307: { const char *s = http_get_header (http, "Location"); log_info (_("URL '%s' redirected to '%s' (%u)\n"), request, s?s:"[none]", http_get_status_code (http)); if (s && *s && redirects_left-- ) { xfree (request_buffer); request_buffer = xtrystrdup (s); if (request_buffer) { request = request_buffer; http_close (http, 0); http = NULL; goto once_more; } err = gpg_error_from_syserror (); } else err = gpg_error (GPG_ERR_NO_DATA); log_error (_("too many redirections\n")); } goto leave; default: log_error (_("error accessing '%s': http status %u\n"), request, http_get_status_code (http)); err = gpg_error (GPG_ERR_NO_DATA); goto leave; } /* FIXME: We should register a permanent redirection and whether a host has ever used TLS so that future calls will always use TLS. */ fp = http_get_read_ptr (http); if (!fp) { err = gpg_error (GPG_ERR_BUG); goto leave; } /* Return the read stream and close the HTTP context. */ *r_fp = fp; http_close (http, 1); http = NULL; leave: http_close (http, 0); http_session_release (session); xfree (request_buffer); return err; }
static int connection_get_reply(struct connection *c, char *resp, int resp_sz) { struct http_request *r; int used = 0; /* * Currently, this doesn't do anything interesting. In the * future it will call the content provider and get the * (ready) response. */ r = c->pending_reqs; if (NULL == r) return 0; while (r) { struct http_request *next; char *local_resp; cbuf_t cb; int consumed, ret, local_resp_sz; assert(r->c == c); if (r->flags & HTTP_REQ_PENDING) break; assert(r->flags & HTTP_REQ_PROCESSED); assert(r->content_id >= 0); /* Previously saved response? */ if (NULL != r->resp.resp) { local_resp = r->resp.resp; local_resp_sz = r->resp.resp_len; } else { int sz; /* Make the request to the content * component */ sz = resp_sz - used; local_resp = cbuf_alloc(sz, &cb); if (!local_resp) BUG(); ret = server_tread(cos_spd_id(), r->content_id, cb, sz); if (ret < 0) { cbuf_free(local_resp); printc("https get reply returning %d.\n", ret); return ret; } local_resp_sz = ret; } /* no more data */ if (local_resp_sz == 0) { cbuf_free(local_resp); break; } /* If the header and data couldn't fit into the * provided buffer, then we need to save the response, * so that we can send it out later... */ if (http_get_header(resp+used, resp_sz-used, local_resp_sz, &consumed)) { if (NULL == r->resp.resp) { char *save; save = malloc(local_resp_sz); assert(save); assert(local_resp); memcpy(save, local_resp, local_resp_sz); cbuf_free(local_resp); local_resp = NULL; r->resp.resp = save; r->resp.resp_len = local_resp_sz; } if (0 == used) { printc("https: could not allocate either header or response of sz %d:%s\n", local_resp_sz, local_resp); if (local_resp) cbuf_free(local_resp); return -ENOMEM; } break; } memcpy(resp+used+consumed, local_resp, local_resp_sz); assert(local_resp); cbuf_free(local_resp); local_resp = NULL; used += local_resp_sz + consumed; next = r->next; /* bookkeeping */ http_req_cnt++; http_free_request(r); r = c->pending_reqs; assert(r == next || NULL == r); } return used; }
static int connection_get_reply(struct connection *c, char *resp, int resp_sz) { struct http_request *r; int used = 0; /* * Currently, this doesn't do anything interesting. In the * future it will call the content provider and get the * (ready) response. */ r = c->pending_reqs; if (NULL == r) return 0; while (r) { struct http_request *next; struct cos_array *arr = NULL; char *local_resp; int *more = NULL; int local_more, consumed, ret, local_resp_sz; assert(r->c == c); if (r->flags & HTTP_REQ_PENDING) break; assert(r->flags & HTTP_REQ_PROCESSED); assert(r->content_id >= 0); /* Previously saved response? */ if (NULL != r->resp.resp) { local_resp = r->resp.resp; local_resp_sz = r->resp.resp_len; local_more = r->resp.more; } else { /* Make the request to the content * component */ more = cos_argreg_alloc(sizeof(int)); assert(more); arr = cos_argreg_alloc(sizeof(struct cos_array) + resp_sz - used); assert(arr); arr->sz = resp_sz - used; if ((ret = content_retrieve(cos_spd_id(), r->content_id, arr, more))) { cos_argreg_free(arr); cos_argreg_free(more); if (0 > ret) { BUG(); /* FIXME send an error message. */ } printc("https get reply returning %d.\n", ret); return ret; } local_more = *more; local_resp_sz = arr->sz; local_resp = arr->mem; } /* still more date, but not available now... */ if (local_resp_sz == 0) { cos_argreg_free(arr); cos_argreg_free(more); break; } /* If the header and data couldn't fit into the * provided buffer, then we need to save the response, * so that we can send it out later... */ if (http_get_header(resp+used, resp_sz-used, local_resp_sz, &consumed)) { if (NULL == r->resp.resp) { char *save; save = malloc(local_resp_sz); assert(save); assert(arr); memcpy(save, arr->mem, local_resp_sz); cos_argreg_free(arr); r->resp.more = *more; cos_argreg_free(more); r->resp.resp = save; r->resp.resp_len = local_resp_sz; } if (0 == used) { printc("https: could not allocate either header or response of sz %d:%s\n", local_resp_sz, local_resp); if (arr) cos_argreg_free(arr); if (more) cos_argreg_free(more); return -ENOMEM; } break; } memcpy(resp+used+consumed, local_resp, local_resp_sz); if (arr) cos_argreg_free(arr); if (more) cos_argreg_free(more); more = NULL; arr = NULL; used += local_resp_sz + consumed; next = r->next; /* bookkeeping */ http_req_cnt++; http_free_request(r); r = c->pending_reqs; assert(r == next || NULL == r); } return used; }
int cgi_ng_pld(http_socket *socket) { u32 content_length; char *file; int mph_len; char *pnt; int len; int i; if (socket->content_priv == 0) { uart_puts("CGI: Start loading PLD.\r\n"); pld_init(); for (i = 0; i < 7500; i++) ; pld_load_start(); pnt = 0; for (i = 0; i < 16; i++) { char arg[16]; pnt = http_get_header(socket, pnt); if (pnt == 0) break; if (strncmp(pnt, "Content-Length:", 15) == 0) { pnt += 16; for (i = 0; i < 7; i++) { if ( (*pnt < '0') || (*pnt > '9') ) break; arg[i] = *pnt; pnt++; } arg[i] = 0; content_length = atoi(arg); break; } } pnt = (char *)socket->rx; while(pnt != 0) { if ( (pnt[0] == 0x0d) && (pnt[1] == 0x0a) && (pnt[2] == 0x0d) && (pnt[3] == 0x0a) ) { /* Get a pointer on datas (after multipart header) */ file = (pnt + 4); break; } /* Search the next CR */ pnt = strchr(pnt + 1, 0x0d); } /* Multipart header length */ mph_len = ((u32)file - (u32)socket->rx); /* Received length */ len = socket->rx_len - mph_len; pld_load((const u8 *)file, len); if (len < content_length) socket->state = HTTP_STATE_RECV_MORE; socket->content_priv = (void *)(content_length - mph_len - len); } else { content_length = (u32)socket->content_priv; pld_load((u8 *)socket->rx, socket->rx_len); if (socket->rx_len < content_length) { socket->content_priv = (void *)(content_length - socket->rx_len); } else { uart_puts("CGI: PLD bitstream loaded !\r\n"); pld_load_end(); socket->content_priv = 0; http_send_header(socket, 200, 0); socket->state = HTTP_STATE_SEND; } } return(0); }
/* Construct an OCSP request, send it to the configured OCSP responder and parse the response. On success the OCSP context may be used to further process the reponse. */ static gpg_error_t do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, const char *url, ksba_cert_t cert, ksba_cert_t issuer_cert) { gpg_error_t err; unsigned char *request, *response; size_t requestlen, responselen; http_t http; ksba_ocsp_response_status_t response_status; const char *t; int redirects_left = 2; char *free_this = NULL; (void)ctrl; if (opt.disable_http) { log_error (_("OCSP request not possible due to disabled HTTP\n")); return gpg_error (GPG_ERR_NOT_SUPPORTED); } err = ksba_ocsp_add_target (ocsp, cert, issuer_cert); if (err) { log_error (_("error setting OCSP target: %s\n"), gpg_strerror (err)); return err; } { size_t n; unsigned char nonce[32]; n = ksba_ocsp_set_nonce (ocsp, NULL, 0); if (n > sizeof nonce) n = sizeof nonce; gcry_create_nonce (nonce, n); ksba_ocsp_set_nonce (ocsp, nonce, n); } err = ksba_ocsp_build_request (ocsp, &request, &requestlen); if (err) { log_error (_("error building OCSP request: %s\n"), gpg_strerror (err)); return err; } once_more: err = http_open (&http, HTTP_REQ_POST, url, NULL, (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0), opt.http_proxy, NULL, NULL, NULL); if (err) { log_error (_("error connecting to '%s': %s\n"), url, gpg_strerror (err)); xfree (free_this); return err; } es_fprintf (http_get_write_ptr (http), "Content-Type: application/ocsp-request\r\n" "Content-Length: %lu\r\n", (unsigned long)requestlen ); http_start_data (http); if (es_fwrite (request, requestlen, 1, http_get_write_ptr (http)) != 1) { err = gpg_error_from_errno (errno); log_error ("error sending request to '%s': %s\n", url, strerror (errno)); http_close (http, 0); xfree (request); xfree (free_this); return err; } xfree (request); request = NULL; err = http_wait_response (http); if (err || http_get_status_code (http) != 200) { if (err) log_error (_("error reading HTTP response for '%s': %s\n"), url, gpg_strerror (err)); else { switch (http_get_status_code (http)) { case 301: case 302: { const char *s = http_get_header (http, "Location"); log_info (_("URL '%s' redirected to '%s' (%u)\n"), url, s?s:"[none]", http_get_status_code (http)); if (s && *s && redirects_left-- ) { xfree (free_this); url = NULL; free_this = xtrystrdup (s); if (!free_this) err = gpg_error_from_errno (errno); else { url = free_this; http_close (http, 0); goto once_more; } } else err = gpg_error (GPG_ERR_NO_DATA); log_error (_("too many redirections\n")); } break; default: log_error (_("error accessing '%s': http status %u\n"), url, http_get_status_code (http)); err = gpg_error (GPG_ERR_NO_DATA); break; } } http_close (http, 0); xfree (free_this); return err; } err = read_response (http_get_read_ptr (http), &response, &responselen); http_close (http, 0); if (err) { log_error (_("error reading HTTP response for '%s': %s\n"), url, gpg_strerror (err)); xfree (free_this); return err; } err = ksba_ocsp_parse_response (ocsp, response, responselen, &response_status); if (err) { log_error (_("error parsing OCSP response for '%s': %s\n"), url, gpg_strerror (err)); xfree (response); xfree (free_this); return err; } switch (response_status) { case KSBA_OCSP_RSPSTATUS_SUCCESS: t = "success"; break; case KSBA_OCSP_RSPSTATUS_MALFORMED: t = "malformed"; break; case KSBA_OCSP_RSPSTATUS_INTERNAL: t = "internal error"; break; case KSBA_OCSP_RSPSTATUS_TRYLATER: t = "try later"; break; case KSBA_OCSP_RSPSTATUS_SIGREQUIRED: t = "must sign request"; break; case KSBA_OCSP_RSPSTATUS_UNAUTHORIZED: t = "unauthorized"; break; case KSBA_OCSP_RSPSTATUS_REPLAYED: t = "replay detected"; break; case KSBA_OCSP_RSPSTATUS_OTHER: t = "other (unknown)"; break; case KSBA_OCSP_RSPSTATUS_NONE: t = "no status"; break; default: t = "[unknown status]"; break; } if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS) { if (opt.verbose) log_info (_("OCSP responder at '%s' status: %s\n"), url, t); err = ksba_ocsp_hash_response (ocsp, response, responselen, HASH_FNC, md); if (err) log_error (_("hashing the OCSP response for '%s' failed: %s\n"), url, gpg_strerror (err)); } else { log_error (_("OCSP responder at '%s' status: %s\n"), url, t); err = gpg_error (GPG_ERR_GENERAL); } xfree (response); xfree (free_this); return err; }
//Cgi that check the request has the correct HOST header //Using it we can ensure our server has a domain of our choice int cgi_check_host(http_connection *connData) { http_server_config *config = (http_server_config*)connData->cgi.argument; if(config==NULL) return HTTPD_CGI_NEXT_RULE; if(config->host_domain==NULL) return HTTPD_CGI_NEXT_RULE; if(connData->state==HTTPD_STATE_ON_URL) { http_set_save_header(connData,HTTP_HOST); return HTTPD_CGI_NEXT_RULE; } if(connData->state==HTTPD_STATE_HEADERS_END) { header *hostHeader = http_get_header(connData,HTTP_HOST); if(hostHeader==NULL) { NODE_ERR("Host header not found\n"); http_response_BAD_REQUEST(connData); return HTTPD_CGI_DONE; } const char * domain = config->host_domain; HTTP_CGI_DBG("Host header: %s, domain: %s\n",hostHeader->value,domain); if(strncmp(hostHeader->value,domain,strlen(domain))==0) //compare ignoring http:// and last / { HTTP_CGI_DBG("Domain match\n"); return HTTPD_CGI_NEXT_RULE; } else{ uint8_t op = wifi_get_opmode(); char ipaddrstr[17]; os_bzero(ipaddrstr, sizeof(ipaddrstr)); struct ip_info ipConfig; switch (op) { case STATIONAP_MODE: { wifi_get_ip_info(SOFTAP_IF,&ipConfig); //0x01 ipaddr_ntoa_r(&ipConfig.ip,ipaddrstr, sizeof(ipaddrstr)); if(strncmp(hostHeader->value,ipaddrstr,strlen(ipaddrstr))==0) { HTTP_CGI_DBG("SoftAp ip match"); return HTTPD_CGI_NEXT_RULE; } } case STATION_MODE: { os_bzero(ipaddrstr, sizeof(ipaddrstr)); wifi_get_ip_info(STATION_IF,&ipConfig); //0x00 ipaddr_ntoa_r(&ipConfig.ip,ipaddrstr, sizeof(ipaddrstr)); if(strncmp(hostHeader->value,ipaddrstr,strlen(ipaddrstr))==0) { HTTP_CGI_DBG("Station ip match"); return HTTPD_CGI_NEXT_RULE; } } } HTTP_CGI_DBG("Hosts don't match\n"); if(config->enable_captive) { //to enable a captive portal we should redirect here char * redirectUrl = (char *)os_zalloc(strlen(domain)+9); // domain length + http:// + / + \0 strcpy(redirectUrl,"http://"); os_strcat(redirectUrl,domain); os_strcat(redirectUrl,"/"); http_response_REDIRECT(connData, redirectUrl); os_free(redirectUrl); HTTP_CGI_DBG("Redirect URL = %s\n", redirectUrl); } else { //bad request else http_response_BAD_REQUEST(connData); } return HTTPD_CGI_DONE; } } return HTTPD_CGI_NEXT_RULE; }
const char * nni_http_res_get_header(nni_http_res *res, const char *key) { return (http_get_header(&res->hdrs, key)); }
const char * nni_http_req_get_header(nni_http_req *req, const char *key) { return (http_get_header(&req->hdrs, key)); }
int main (int argc, char **argv) { int last_argc = -1; gpg_error_t err; int rc; parsed_uri_t uri; uri_tuple_t r; http_t hd; int c; unsigned int my_http_flags = 0; int no_out = 0; int tls_dbg = 0; const char *cafile = NULL; http_session_t session = NULL; gpgrt_init (); log_set_prefix (PGM, 1 | 4); if (argc) { argc--; argv++; } while (argc && last_argc != argc ) { last_argc = argc; if (!strcmp (*argv, "--")) { argc--; argv++; break; } else if (!strcmp (*argv, "--help")) { fputs ("usage: " PGM " URL\n" "Options:\n" " --verbose print timings etc.\n" " --debug flyswatter\n" " --gnutls-debug N use GNUTLS debug level N\n" " --cacert FNAME expect CA certificate in file FNAME\n" " --no-verify do not verify the certificate\n" " --force-tls use HTTP_FLAG_FORCE_TLS\n" " --no-out do not print the content\n", stdout); exit (0); } else if (!strcmp (*argv, "--verbose")) { verbose++; argc--; argv++; } else if (!strcmp (*argv, "--debug")) { verbose += 2; debug++; argc--; argv++; } else if (!strcmp (*argv, "--gnutls-debug")) { argc--; argv++; if (argc) { tls_dbg = atoi (*argv); argc--; argv++; } } else if (!strcmp (*argv, "--cacert")) { argc--; argv++; if (argc) { cafile = *argv; argc--; argv++; } } else if (!strcmp (*argv, "--no-verify")) { no_verify = 1; argc--; argv++; } else if (!strcmp (*argv, "--force-tls")) { my_http_flags |= HTTP_FLAG_FORCE_TLS; argc--; argv++; } else if (!strcmp (*argv, "--no-out")) { no_out = 1; argc--; argv++; } else if (!strncmp (*argv, "--", 2)) { fprintf (stderr, PGM ": unknown option '%s'\n", *argv); exit (1); } } if (argc != 1) { fprintf (stderr, PGM ": no or too many URLS given\n"); exit (1); } if (!cafile) cafile = prepend_srcdir ("tls-ca.pem"); #if HTTP_USE_NTBTLS (void)err; ntbtls_set_debug (tls_dbg, NULL, NULL); #elif HTTP_USE_GNUTLS rc = gnutls_global_init (); if (rc) log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc)); http_register_tls_callback (verify_callback); http_register_tls_ca (cafile); err = http_session_new (&session, NULL); if (err) log_error ("http_session_new failed: %s\n", gpg_strerror (err)); /* rc = gnutls_dh_params_init(&dh_params); */ /* if (rc) */ /* log_error ("gnutls_dh_params_init failed: %s\n", gnutls_strerror (rc)); */ /* read_dh_params ("dh_param.pem"); */ /* rc = gnutls_certificate_set_x509_trust_file */ /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */ /* if (rc) */ /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */ /* gnutls_strerror (rc)); */ /* gnutls_certificate_set_dh_params (certcred, dh_params); */ gnutls_global_set_log_function (my_gnutls_log); if (tls_dbg) gnutls_global_set_log_level (tls_dbg); #endif /*HTTP_USE_GNUTLS*/ rc = http_parse_uri (&uri, *argv, 1); if (rc) { log_error ("'%s': %s\n", *argv, gpg_strerror (rc)); return 1; } printf ("Scheme: %s\n", uri->scheme); if (uri->opaque) printf ("Value : %s\n", uri->path); else { printf ("Auth : %s\n", uri->auth? uri->auth:"[none]"); printf ("Host : %s\n", uri->host); printf ("Port : %u\n", uri->port); printf ("Path : %s\n", uri->path); for (r = uri->params; r; r = r->next) { printf ("Params: %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } for (r = uri->query; r; r = r->next) { printf ("Query : %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } printf ("TLS : %s\n", uri->use_tls? "yes": (my_http_flags&HTTP_FLAG_FORCE_TLS)? "forced" : "no"); } fflush (stdout); http_release_parsed_uri (uri); uri = NULL; rc = http_open_document (&hd, *argv, NULL, my_http_flags, NULL, session, NULL, NULL); if (rc) { log_error ("can't get '%s': %s\n", *argv, gpg_strerror (rc)); return 1; } log_info ("open_http_document succeeded; status=%u\n", http_get_status_code (hd)); { const char **names; int i; names = http_get_header_names (hd); if (!names) log_fatal ("http_get_header_names failed: %s\n", gpg_strerror (gpg_error_from_syserror ())); for (i = 0; names[i]; i++) printf ("HDR: %s: %s\n", names[i], http_get_header (hd, names[i])); xfree (names); } fflush (stdout); switch (http_get_status_code (hd)) { case 200: case 400: case 401: case 403: case 404: { unsigned long count = 0; while ((c = es_getc (http_get_read_ptr (hd))) != EOF) { count++; if (!no_out) putchar (c); } log_info ("Received bytes: %lu\n", count); } break; case 301: case 302: case 307: log_info ("Redirected to: %s\n", http_get_header (hd, "Location")); break; } http_close (hd, 0); http_session_release (session); #ifdef HTTP_USE_GNUTLS gnutls_global_deinit (); #endif /*HTTP_USE_GNUTLS*/ return 0; }
int main (int argc, char **argv) { gpg_error_t err; int rc; parsed_uri_t uri; uri_tuple_t r; http_t hd; int c; http_session_t session = NULL; gpgrt_init (); log_set_prefix ("t-http", 1 | 4); if (argc != 2) { fprintf (stderr, "usage: t-http uri\n"); return 1; } argc--; argv++; #ifdef HTTP_USE_GNUTLS rc = gnutls_global_init (); if (rc) log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc)); http_register_tls_callback (verify_callback); http_register_tls_ca ("tls-ca.pem"); err = http_session_new (&session, NULL); if (err) log_error ("http_session_new failed: %s\n", gpg_strerror (err)); /* rc = gnutls_dh_params_init(&dh_params); */ /* if (rc) */ /* log_error ("gnutls_dh_params_init failed: %s\n", gnutls_strerror (rc)); */ /* read_dh_params ("dh_param.pem"); */ /* rc = gnutls_certificate_set_x509_trust_file */ /* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */ /* if (rc) */ /* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */ /* gnutls_strerror (rc)); */ /* gnutls_certificate_set_dh_params (certcred, dh_params); */ gnutls_global_set_log_function (my_gnutls_log); /* gnutls_global_set_log_level (2); */ #endif /*HTTP_USE_GNUTLS*/ rc = http_parse_uri (&uri, *argv, 1); if (rc) { log_error ("'%s': %s\n", *argv, gpg_strerror (rc)); return 1; } printf ("Scheme: %s\n", uri->scheme); if (uri->opaque) printf ("Value : %s\n", uri->path); else { printf ("Auth : %s\n", uri->auth? uri->auth:"[none]"); printf ("Host : %s\n", uri->host); printf ("Port : %u\n", uri->port); printf ("Path : %s\n", uri->path); for (r = uri->params; r; r = r->next) { printf ("Params: %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } for (r = uri->query; r; r = r->next) { printf ("Query : %s", r->name); if (!r->no_value) { printf ("=%s", r->value); if (strlen (r->value) != r->valuelen) printf (" [real length=%d]", (int) r->valuelen); } putchar ('\n'); } } http_release_parsed_uri (uri); uri = NULL; rc = http_open_document (&hd, *argv, NULL, 0, NULL, session, NULL, NULL); if (rc) { log_error ("can't get '%s': %s\n", *argv, gpg_strerror (rc)); return 1; } log_info ("open_http_document succeeded; status=%u\n", http_get_status_code (hd)); { const char **names; int i; names = http_get_header_names (hd); if (!names) log_fatal ("http_get_header_names failed: %s\n", gpg_strerror (gpg_error_from_syserror ())); for (i = 0; names[i]; i++) printf ("HDR: %s: %s\n", names[i], http_get_header (hd, names[i])); xfree (names); } switch (http_get_status_code (hd)) { case 200: case 400: case 401: case 403: case 404: while ((c = es_getc (http_get_read_ptr (hd))) != EOF) putchar (c); break; case 301: case 302: printf ("Redirected to '%s'\n", http_get_header (hd, "Location")); break; } http_close (hd, 0); http_session_release (session); #ifdef HTTP_USE_GNUTLS gnutls_global_deinit (); #endif /*HTTP_USE_GNUTLS*/ return 0; }