bool RESTRequestState::get_client_addr(p4p::IPPrefix& addr) const { #if MHD_VERSION >= 0x00040001 const MHD_ConnectionInfo* cinfo = MHD_get_connection_info(conn_, MHD_CONNECTION_INFO_CLIENT_ADDRESS); if (!cinfo) return false; const struct sockaddr_in* saddr = (const struct sockaddr_in*) cinfo->client_addr; if (!saddr) return false; if (saddr->sin_family == AF_INET) { addr = p4p::IPPrefix(AF_INET, &saddr->sin_addr, sizeof(saddr->sin_addr) * 8); return true; } const struct sockaddr_in6* saddr6 = (const struct sockaddr_in6*)saddr; if (saddr6->sin6_family == AF_INET6) { addr = p4p::IPPrefix(AF_INET6, &saddr6->sin6_addr, sizeof(saddr6->sin6_addr) * 8); return true; } #endif return false; }
std::string getIP(struct MHD_Connection *connection) { char address[INET_ADDRSTRLEN]; inet_ntop(AF_INET, (void *) &((struct sockaddr_in *)MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS)->client_addr)->sin_addr, address, INET_ADDRSTRLEN); return std::string(address); }
/* * HTTP access handler call back * used to query negotiated security parameters */ static int query_session_ahc (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *upload_data, const char *version, size_t *upload_data_size, void **ptr) { struct MHD_Response *response; int ret; if (NULL == *ptr) { *ptr = &query_session_ahc; return MHD_YES; } /* assert actual connection cipher is the one negotiated */ if (GNUTLS_CIPHER_AES_256_CBC != (ret = MHD_get_connection_info (connection, MHD_CONNECTION_INFO_CIPHER_ALGO)->cipher_algorithm)) { fprintf (stderr, "Error: requested cipher mismatch (wanted %d, got %d)\n", GNUTLS_CIPHER_AES_256_CBC, ret); return -1; } if (GNUTLS_SSL3 != (ret = MHD_get_connection_info (connection, MHD_CONNECTION_INFO_PROTOCOL)->protocol)) { fprintf (stderr, "Error: requested protocol mismatch (wanted %d, got %d)\n", GNUTLS_SSL3, ret); return -1; } response = MHD_create_response_from_data (strlen (EMPTY_PAGE), (void *) EMPTY_PAGE, MHD_NO, MHD_NO); ret = MHD_queue_response (connection, MHD_HTTP_OK, response); MHD_destroy_response (response); return ret; }
int check_permissions(struct MHD_Connection *connection, int *code, char **hostname) { const union MHD_ConnectionInfo *ci; gnutls_session_t session; gnutls_x509_crt_t client_cert; _cleanup_free_ char *buf = NULL; int r; assert(connection); assert(code); *code = 0; ci = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_GNUTLS_SESSION); if (!ci) { log_error("MHD_get_connection_info failed: session is unencrypted"); *code = mhd_respond(connection, MHD_HTTP_FORBIDDEN, "Encrypted connection is required"); return -EPERM; } session = ci->tls_session; assert(session); r = get_client_cert(session, &client_cert); if (r < 0) { *code = mhd_respond(connection, MHD_HTTP_UNAUTHORIZED, "Authorization through certificate is required"); return -EPERM; } r = get_auth_dn(client_cert, &buf); if (r < 0) { *code = mhd_respond(connection, MHD_HTTP_UNAUTHORIZED, "Failed to determine distinguished name from certificate"); return -EPERM; } log_info("Connection from %s", buf); if (hostname) { *hostname = buf; buf = NULL; } r = verify_cert_authorized(session); if (r < 0) { log_warning("Client is not authorized"); *code = mhd_respond(connection, MHD_HTTP_UNAUTHORIZED, "Client certificate not signed by recognized authority"); } return r; }
void http_response::get_raw_response_lp_receive( MHD_Response** response, webserver* ws ) { this->ws = ws; this->connection_id = MHD_get_connection_info( this->underlying_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS )->client_addr; *response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 80, &http_response::data_generator, (void*) this, NULL); ws->register_to_topics( topics, connection_id, keepalive_secs, keepalive_msg ); }
static void log_request(struct MHD_Connection *connection, const struct http_priv_t *http, const char *method, const char *url) { #if MHD_VERSION < 0x00090600 const union MHD_ConnectionInfo *info; const unsigned char *ip; info = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); assert(info); ip = (unsigned char *)&info->client_addr->sin_addr.s_addr; logger(http->logger, "%hhu.%hhu.%hhu.%hhu:%d - %s %s", ip[0], ip[1], ip[2], ip[3], info->client_addr->sin_port, method, url); #else (void)connection; logger(http->logger, "%s %s", method, url); #endif }
/** * @brief get_ip * @param connection * @return ip address - must be freed by caller */ static char * get_ip(struct MHD_Connection *connection) { const union MHD_ConnectionInfo *connection_info; char *ip_addr = NULL; const struct sockaddr *client_addr; const struct sockaddr_in *addrin; const struct sockaddr_in6 *addrin6; if (!(connection_info = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS))) { return NULL; } /* cast required for legacy MHD API < 0.9.6*/ client_addr = (const struct sockaddr *)connection_info->client_addr; addrin = (const struct sockaddr_in *) client_addr; addrin6 = (const struct sockaddr_in6 *) client_addr; switch(client_addr->sa_family) { case AF_INET: ip_addr = calloc(1, INET_ADDRSTRLEN+1); if(!inet_ntop(addrin->sin_family, &(addrin->sin_addr), ip_addr , sizeof(struct sockaddr_in))) { free(ip_addr); return NULL; } break; case AF_INET6: ip_addr = calloc(1, INET6_ADDRSTRLEN+1); if(!inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr), ip_addr , sizeof(struct sockaddr_in6))) { free(ip_addr); return NULL; } break; } return ip_addr; }
/* **************************************************************************** * * connectionTreat - * * This is the MHD_AccessHandlerCallback function for MHD_start_daemon * This function returns: * o MHD_YES if the connection was handled successfully * o MHD_NO if the socket must be closed due to a serious error * * - This function is called once when the headers are read and the ciP is created. * - Then it is called for data payload and once all the payload an acknowledgement * must be done, setting *upload_data_size to ZERO. * - The last call is made with *upload_data_size == 0 and now is when the connection * is open to send responses. * * Call 1: *con_cls == NULL * Call 2: *con_cls != NULL AND *upload_data_size != 0 * Call 3: *con_cls != NULL AND *upload_data_size == 0 */ static int connectionTreat ( void* cls, MHD_Connection* connection, const char* url, const char* method, const char* version, const char* upload_data, size_t* upload_data_size, void** con_cls ) { ConnectionInfo* ciP = (ConnectionInfo*) *con_cls; size_t dataLen = *upload_data_size; // 1. First call - setup ConnectionInfo and get/check HTTP headers if (ciP == NULL) { // // IP Address and port of caller // char ip[32]; unsigned short port = 0; const union MHD_ConnectionInfo* mciP = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); if (mciP != NULL) { port = (mciP->client_addr->sa_data[0] << 8) + mciP->client_addr->sa_data[1]; snprintf(ip, sizeof(ip), "%d.%d.%d.%d", mciP->client_addr->sa_data[2] & 0xFF, mciP->client_addr->sa_data[3] & 0xFF, mciP->client_addr->sa_data[4] & 0xFF, mciP->client_addr->sa_data[5] & 0xFF); } else { port = 0; snprintf(ip, sizeof(ip), "IP unknown"); } // // ConnectionInfo // if ((ciP = new ConnectionInfo(url, method, version, connection)) == NULL) { LM_E(("Runtime Error (error allocating ConnectionInfo)")); return MHD_NO; } *con_cls = (void*) ciP; // Pointer to ConnectionInfo for subsequent calls ciP->port = port; ciP->ip = ip; // // Transaction starts here // LM_TRANSACTION_START("from", ip, port, url); // Incoming REST request starts // // URI parameters // ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] = DEFAULT_PARAM_NOTIFY_FORMAT; ciP->uriParam[URI_PARAM_PAGINATION_OFFSET] = DEFAULT_PAGINATION_OFFSET; ciP->uriParam[URI_PARAM_PAGINATION_LIMIT] = DEFAULT_PAGINATION_LIMIT; ciP->uriParam[URI_PARAM_PAGINATION_DETAILS] = DEFAULT_PAGINATION_DETAILS; MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, uriArgumentGet, ciP); if (ciP->httpStatusCode != SccOk) { LM_W(("Bad Input (error in URI parameters)")); restReply(ciP, ciP->answer); return MHD_YES; } LM_T(LmtUriParams, ("notifyFormat: '%s'", ciP->uriParam[URI_PARAM_NOTIFY_FORMAT].c_str())); MHD_get_connection_values(connection, MHD_HEADER_KIND, httpHeaderGet, &ciP->httpHeaders); char tenant[128]; ciP->tenantFromHttpHeader = strToLower(tenant, ciP->httpHeaders.tenant.c_str(), sizeof(tenant)); LM_T(LmtTenant, ("HTTP tenant: '%s'", ciP->httpHeaders.tenant.c_str())); ciP->outFormat = wantedOutputSupported(ciP->httpHeaders.accept, &ciP->charset); if (ciP->outFormat == NOFORMAT) ciP->outFormat = XML; // XML is default output format ciP->servicePath = ciP->httpHeaders.servicePath; if (servicePathSplit(ciP) != 0) { LM_W(("Bad Input (error in ServicePath http-header)")); restReply(ciP, ciP->answer); } if (contentTypeCheck(ciP) != 0) { LM_W(("Bad Input (invalid mime-type in Content-Type http-header)")); restReply(ciP, ciP->answer); } else if (outFormatCheck(ciP) != 0) { LM_W(("Bad Input (invalid mime-type in Accept http-header)")); restReply(ciP, ciP->answer); } else ciP->inFormat = formatParse(ciP->httpHeaders.contentType, NULL); // Set default mime-type for notifications if (ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] == "") { if (ciP->outFormat == XML) ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] = "XML"; else if (ciP->outFormat == JSON) ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] = "JSON"; else ciP->uriParam[URI_PARAM_NOTIFY_FORMAT] = "XML"; LM_T(LmtUriParams, ("'default' value for notifyFormat (ciP->outFormat == %d)): '%s'", ciP->outFormat, ciP->uriParam[URI_PARAM_NOTIFY_FORMAT].c_str())); } return MHD_YES; } // // 2. Data gathering calls // // 2-1. Data gathering calls, just wait // 2-2. Last data gathering call, acknowledge the receipt of data // if (dataLen != 0) { if (dataLen == ciP->httpHeaders.contentLength) { if (ciP->httpHeaders.contentLength <= PAYLOAD_MAX_SIZE) { if (ciP->httpHeaders.contentLength > STATIC_BUFFER_SIZE) ciP->payload = (char*) malloc(ciP->httpHeaders.contentLength + 1); else ciP->payload = static_buffer; ciP->payloadSize = dataLen; memcpy(ciP->payload, upload_data, dataLen); ciP->payload[dataLen] = 0; } else { char details[256]; snprintf(details, sizeof(details), "payload size: %d, max size supported: %d", ciP->httpHeaders.contentLength, PAYLOAD_MAX_SIZE); ciP->answer = restErrorReplyGet(ciP, ciP->outFormat, "", ciP->url, SccRequestEntityTooLarge, details); ciP->httpStatusCode = SccRequestEntityTooLarge; } // All payload received, acknowledge! *upload_data_size = 0; } else LM_T(LmtPartialPayload, ("Got %d of payload of %d bytes", dataLen, ciP->httpHeaders.contentLength)); return MHD_YES; } // 3. Finally, serve the request (unless an error has occurred) if (((ciP->verb == POST) || (ciP->verb == PUT)) && (ciP->httpHeaders.contentLength == 0) && (strncasecmp(ciP->url.c_str(), "/log/", 5) != 0)) { std::string errorMsg = restErrorReplyGet(ciP, ciP->outFormat, "", url, SccLengthRequired, "Zero/No Content-Length in PUT/POST request"); ciP->httpStatusCode = SccLengthRequired; restReply(ciP, errorMsg); } else if (ciP->answer != "") restReply(ciP, ciP->answer); else serveFunction(ciP); return MHD_YES; }
// When we receive the CoAP response we build and send the HTTP response void coap_response_handler(struct coap_context_t *ctx, const coap_endpoint_t *local_interface, const coap_address_t *remote, coap_pdu_t *sent, coap_pdu_t *received, const coap_tid_t id) { printf("COAP %13s:%-5u -> ", inet_ntoa((&remote->addr.sin)->sin_addr), ntohs((&remote->addr.sin)->sin_port)); coap_show_pdu(received); for(int i = 0; i < MAX_HTTP_CONNECTIONS; i++) { if(http_coap_pairs[i].message_id == received->hdr->id) { struct MHD_Connection *connection = http_coap_pairs[i].connection; size_t len = 0; unsigned char *databuf = NULL; struct MHD_Response *response = MHD_create_response_from_buffer(len, databuf, MHD_RESPMEM_MUST_COPY); int read_result = coap_get_data(received, &len, &databuf); if(received->hdr->code == COAP_RESPONSE_CODE(205) && read_result == 0) { coap_abort_to_http(connection, "coap_get_data: cannot read CoAP response data\n"); } static char tid_str[8]; snprintf(tid_str, sizeof(tid_str), "%u", ntohs(received->hdr->id)); MHD_add_response_header(response, "X-CoAP-Message-Id", tid_str); MHD_add_response_header(response, "X-CoAP-Response-Code", msg_code_string(received->hdr->code)); // HTTP Content-Type const char *http_content_type; int coap_content_format; coap_opt_iterator_t opt_iter; coap_opt_t *option; coap_option_iterator_init(received, &opt_iter, COAP_OPT_ALL); while((option = coap_option_next(&opt_iter))) { switch(opt_iter.type) { case COAP_OPTION_CONTENT_FORMAT: coap_content_format = (int)coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option)); break; default: continue; } } switch(coap_content_format) { case COAP_MEDIATYPE_TEXT_PLAIN: http_content_type = "text/plain"; break; case COAP_MEDIATYPE_APPLICATION_LINK_FORMAT: http_content_type = "application/link-format"; break; case COAP_MEDIATYPE_APPLICATION_XML: http_content_type = "application/xml"; break; case COAP_MEDIATYPE_APPLICATION_OCTET_STREAM: http_content_type = "application/octet-stream"; break; case COAP_MEDIATYPE_APPLICATION_EXI: http_content_type = "application/exi"; break; case COAP_MEDIATYPE_APPLICATION_JSON: http_content_type = "application/json"; break; case COAP_MEDIATYPE_APPLICATION_CBOR: http_content_type = "application/cbor"; break; default: http_content_type = "unknown"; break; } MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, http_content_type); // HTTP Code unsigned int http_code; switch(received->hdr->code) { case COAP_RESPONSE_200: http_code = MHD_HTTP_NO_CONTENT; break; /* 2.00 OK */ case COAP_RESPONSE_201: http_code = MHD_HTTP_CREATED; break; /* 2.01 Created */ case COAP_RESPONSE_CODE(205): http_code = MHD_HTTP_OK; break; case COAP_RESPONSE_304: http_code = MHD_HTTP_ACCEPTED; break; /* 2.03 Valid */ case COAP_RESPONSE_400: http_code = MHD_HTTP_BAD_REQUEST; break; /* 4.00 Bad Request */ case COAP_RESPONSE_404: http_code = MHD_HTTP_NOT_FOUND; break; /* 4.04 Not Found */ case COAP_RESPONSE_405: http_code = MHD_HTTP_NOT_ACCEPTABLE; break; /* 4.05 Method Not Allowed */ case COAP_RESPONSE_415: http_code = MHD_HTTP_UNSUPPORTED_MEDIA_TYPE;break; /* 4.15 Unsupported Media Type */ case COAP_RESPONSE_500: http_code = MHD_HTTP_INTERNAL_SERVER_ERROR; break; /* 5.00 Internal Server Error */ case COAP_RESPONSE_501: http_code = MHD_HTTP_NOT_IMPLEMENTED; break; /* 5.01 Not Implemented */ case COAP_RESPONSE_503: http_code = MHD_HTTP_SERVICE_UNAVAILABLE; break; /* 5.03 Service Unavailable */ case COAP_RESPONSE_504: http_code = MHD_HTTP_GATEWAY_TIMEOUT; break; /* 5.04 Gateway Timeout */ default: http_code = MHD_HTTP_INTERNAL_SERVER_ERROR; break; } // Send the response MHD_queue_response(connection, http_code, response); MHD_destroy_response(response); const struct sockaddr_in *client_addr = (const struct sockaddr_in *) MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS)->client_addr; printf("HTTP %13s:%-5u <- %u %s [ %s, %zu bytes, \"%s\" ]\n", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port), http_code, http_reason_phrase_for(http_code), http_content_type, len, (databuf != NULL) ? (char *)databuf : ""); } // clear the association http_coap_pairs[i].connection = NULL; return; } }
int answer_to_connection (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) { str page = {NULL, 0}; struct MHD_Response *response; int ret; void *async_data = NULL; struct httpd_cb *cb = NULL; const char *normalised_url; struct post_request *pr; str_str_t *kv; char *p; int cnt_type = HTTPD_STD_CNT_TYPE; int accept_type = HTTPD_STD_CNT_TYPE; int ret_code = MHD_HTTP_OK; union sockaddr_union* cl_socket; LM_DBG("START *** cls=%p, connection=%p, url=%s, method=%s, " "versio=%s, upload_data[%zu]=%p, *con_cls=%p\n", cls, connection, url, method, version, *upload_data_size, upload_data, *con_cls); pr = *con_cls; if(pr == NULL){ pr = pkg_malloc(sizeof(struct post_request)); if(pr==NULL) { LM_ERR("oom while allocating post_request structure\n"); return MHD_NO; } memset(pr, 0, sizeof(struct post_request)); *con_cls = pr; pr = NULL; } cl_socket = *(union sockaddr_union**)MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); if(strncmp(method, "POST", 4)==0) { if(pr == NULL){ pr = *con_cls; pr->p_list = slinkedl_init(&httpd_alloc, &httpd_free); if (pr->p_list==NULL) { LM_ERR("oom while allocating list\n"); return MHD_NO; } LM_DBG("running MHD_create_post_processor\n"); pr->pp = MHD_create_post_processor(connection, post_buf_size, &post_iterator, pr); if(pr->pp==NULL) { if (*upload_data_size == 0) { /* We need to wait for morte data before * handling the POST request */ return MHD_YES; } LM_DBG("NOT a regular POST :o)\n"); if (pr->content_type==0 && pr->content_len==0) MHD_get_connection_values(connection, MHD_HEADER_KIND, &getConnectionHeader, pr); if (pr->content_type<=0 || pr->content_len<=0) { LM_ERR("got a bogus request\n"); return MHD_NO; } if (*upload_data_size != pr->content_len) { /* For now, we don't support large POST with truncated data */ LM_ERR("got a truncated POST request\n"); return MHD_NO; } LM_DBG("got ContentType [%d] with len [%d]: %.*s\\n", pr->content_type, pr->content_len, (int)*upload_data_size, upload_data); /* Here we save data. */ switch (pr->content_type) { case HTTPD_TEXT_XML_CNT_TYPE: case HTTPD_APPLICATION_JSON_CNT_TYPE: /* Save the entire body as 'body' */ kv = (str_str_t*)slinkedl_append(pr->p_list, sizeof(str_str_t) + 1 + *upload_data_size); p = (char*)(kv + 1); kv->key.len = 1; kv->key.s = p; memcpy(p, "1", 1); p += 1; kv->val.len = *upload_data_size; kv->val.s = p; memcpy(p, upload_data, *upload_data_size); break; default: LM_ERR("Unhandled data for ContentType [%d]\n", pr->content_type); return MHD_NO; } /* Mark the fact that we consumed all data */ *upload_data_size = 0; return MHD_YES; } LM_DBG("pr=[%p] pp=[%p] p_list=[%p]\n", pr, pr->pp, pr->p_list); return MHD_YES; } else { if (pr->pp==NULL) { if (*upload_data_size == 0) { if (pr->content_type==HTTPD_TEXT_XML_CNT_TYPE) cnt_type = HTTPD_TEXT_XML_CNT_TYPE; if (pr->content_type==HTTPD_APPLICATION_JSON_CNT_TYPE) cnt_type = HTTPD_APPLICATION_JSON_CNT_TYPE; *con_cls = pr->p_list; cb = get_httpd_cb(url); if (cb) { normalised_url = &url[cb->http_root->len+1]; LM_DBG("normalised_url=[%s]\n", normalised_url); ret_code = cb->callback(cls, (void*)connection, normalised_url, method, version, upload_data, upload_data_size, con_cls, &buffer, &page, cl_socket); } else { page = MI_HTTP_U_URL; ret_code = MHD_HTTP_BAD_REQUEST; } /* slinkedl_traverse(pr->p_list, &httpd_print_data, NULL, NULL); */ slinkedl_list_destroy(*con_cls); pkg_free(pr); *con_cls = pr = NULL; goto send_response; } LM_DBG("NOT a regular POST :o)\n"); if (pr->content_type==0 && pr->content_len==0) MHD_get_connection_values(connection, MHD_HEADER_KIND, &getConnectionHeader, pr); if (pr->content_type<=0 || pr->content_len<=0) { LM_ERR("got a bogus request\n"); return MHD_NO; } if (*upload_data_size != pr->content_len) { /* For now, we don't support large POST with truncated data */ LM_ERR("got a truncated POST request\n"); return MHD_NO; } LM_DBG("got ContentType [%d] with len [%d]: %.*s\\n", pr->content_type, pr->content_len, (int)*upload_data_size, upload_data); /* Here we save data. */ switch (pr->content_type) { case HTTPD_TEXT_XML_CNT_TYPE: case HTTPD_APPLICATION_JSON_CNT_TYPE: /* Save the entire body as 'body' */ kv = (str_str_t*)slinkedl_append(pr->p_list, sizeof(str_str_t) + 1 + *upload_data_size); p = (char*)(kv + 1); kv->key.len = 1; kv->key.s = p; memcpy(p, "1", 1); p += 1; kv->val.len = *upload_data_size; kv->val.s = p; memcpy(p, upload_data, *upload_data_size); break; default: LM_ERR("Unhandled data for ContentType [%d]\n", pr->content_type); return MHD_NO; } /* Mark the fact that we consumed all data */ *upload_data_size = 0; return MHD_YES; } LM_DBG("running MHD_post_process: " "pp=%p status=%d upload_data_size=%zu\n", pr->pp, pr->status, *upload_data_size); if (pr->status<0) { slinkedl_list_destroy(pr->p_list); pr->p_list = NULL; /* FIXME: * It might be better to reply with an error * instead of resetting the connection via MHD_NO */ return MHD_NO; } ret =MHD_post_process(pr->pp, upload_data, *upload_data_size); LM_DBG("ret=%d upload_data_size=%zu\n", ret, *upload_data_size); if(*upload_data_size != 0) { *upload_data_size = 0; return MHD_YES; } LM_DBG("running MHD_destroy_post_processor: " "pr=[%p] pp=[%p] p_list=[%p]\n", pr, pr->pp, pr->p_list); MHD_destroy_post_processor(pr->pp); LM_DBG("done MHD_destroy_post_processor\n"); /* slinkedl_traverse(pr->p_list, &httpd_print_data, NULL, NULL); */ *con_cls = pr->p_list; cb = get_httpd_cb(url); if (cb) { normalised_url = &url[cb->http_root->len+1]; LM_DBG("normalised_url=[%s]\n", normalised_url); ret_code = cb->callback(cls, (void*)connection, normalised_url, method, version, upload_data, upload_data_size, con_cls, &buffer, &page, cl_socket); } else { page = MI_HTTP_U_URL; ret_code = MHD_HTTP_BAD_REQUEST; } /* slinkedl_traverse(pr->p_list, &httpd_print_data, NULL, NULL); */ slinkedl_list_destroy(*con_cls); pkg_free(pr); *con_cls = pr = NULL; } }else if(strncmp(method, "GET", 3)==0) { pr = *con_cls; MHD_get_connection_values(connection, MHD_HEADER_KIND, &getConnectionHeader, pr); accept_type = pr->accept_type; pkg_free(pr); *con_cls = pr = NULL; LM_DBG("accept_type=[%d]\n", accept_type); cb = get_httpd_cb(url); if (cb) { normalised_url = &url[cb->http_root->len+1]; LM_DBG("normalised_url=[%s]\n", normalised_url); ret_code = cb->callback(cls, (void*)connection, normalised_url, method, version, upload_data, upload_data_size, con_cls, &buffer, &page, cl_socket); } else { page = MI_HTTP_U_URL; ret_code = MHD_HTTP_BAD_REQUEST; } }else{ page = MI_HTTP_U_METHOD; #ifdef MHD_HTTP_NOT_ACCEPTABLE ret_code = MHD_HTTP_NOT_ACCEPTABLE; #else ret_code = MHD_HTTP_METHOD_NOT_ACCEPTABLE; #endif } send_response: if (page.s) { #if defined MHD_VERSION && MHD_VERSION >= 0x00090000 response = MHD_create_response_from_buffer(page.len, (void*)page.s, MHD_RESPMEM_MUST_COPY); #else /* use old constructor */ response = MHD_create_response_from_data(page.len, (void*)page.s, 0, 1); #endif LM_DBG("MHD_create_response_from_data [%p:%d]\n", page.s, page.len); } else if (cb) { LM_DBG("MHD_create_response_from_callback\n"); response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, buffer.len, (MHD_ContentReaderCallback)cb->flush_data_callback, (void*)async_data, NULL); } else { return -1; } if (cnt_type==HTTPD_TEXT_XML_CNT_TYPE || accept_type==HTTPD_TEXT_XML_CNT_TYPE) MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, "text/xml; charset=utf-8"); if (cnt_type==HTTPD_APPLICATION_JSON_CNT_TYPE || accept_type==HTTPD_APPLICATION_JSON_CNT_TYPE) MHD_add_response_header(response, MHD_HTTP_HEADER_CONTENT_TYPE, "application/json"); ret = MHD_queue_response (connection, ret_code, response); MHD_destroy_response (response); return ret; }
static ssize_t http_cb_response (void *cls, uint64_t pos, char *buffer, size_t max) { (void)pos; int ret; struct Proxy *proxy = (struct Proxy *)cls; void *newbody; const union MHD_ConnectionInfo *info; int val = 1; PRINT_INFO2("http_cb_response for %s", proxy->url); if(proxy->spdy_error) return MHD_CONTENT_READER_END_WITH_ERROR; if(0 == proxy->http_body_size && (proxy->done || !proxy->spdy_active)) { PRINT_INFO("sent end of stream"); return MHD_CONTENT_READER_END_OF_STREAM; } if(!proxy->http_body_size)//nothing to write now { //flush data info = MHD_get_connection_info (proxy->http_connection, MHD_CONNECTION_INFO_CONNECTION_FD); ret = setsockopt(info->connect_fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val)); if(ret == -1) { DIE("setsockopt"); } PRINT_INFO("FLUSH data"); return 0; } if(max >= proxy->http_body_size) { ret = proxy->http_body_size; newbody = NULL; } else { ret = max; if(NULL == (newbody = au_malloc(proxy->http_body_size - max))) { PRINT_INFO("no memory"); return MHD_CONTENT_READER_END_WITH_ERROR; } memcpy(newbody, proxy->http_body + max, proxy->http_body_size - max); } memcpy(buffer, proxy->http_body, ret); free(proxy->http_body); proxy->http_body = newbody; proxy->http_body_size -= ret; if(proxy->length >= 0) { proxy->length -= ret; } PRINT_INFO2("response_callback, size: %i",ret); return ret; }
static int connectionTreat ( void* cls, MHD_Connection* connection, const char* url, const char* method, const char* version, const char* upload_data, size_t* upload_data_size, void** con_cls ) { ConnectionInfo* ciP = (ConnectionInfo*) *con_cls; size_t dataLen = *upload_data_size; // 1. First call - setup ConnectionInfo and get/check HTTP headers if (ciP == NULL) { // // First thing to do on a new connection, set correlator to N/A. // After reading HTTP headers, the correlator id either changes due to encountering a // Fiware-Correlator HTTP Header, or, if no HTTP header with Fiware-Correlator is found, // a new correlator is generated. // correlatorIdSet("N/A"); // // IP Address and port of caller // char ip[32]; unsigned short port = 0; const union MHD_ConnectionInfo* mciP = MHD_get_connection_info(connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); if (mciP != NULL) { struct sockaddr* addr = (struct sockaddr*) mciP->client_addr; port = (addr->sa_data[0] << 8) + addr->sa_data[1]; snprintf(ip, sizeof(ip), "%d.%d.%d.%d", addr->sa_data[2] & 0xFF, addr->sa_data[3] & 0xFF, addr->sa_data[4] & 0xFF, addr->sa_data[5] & 0xFF); snprintf(clientIp, sizeof(clientIp), "%s", ip); } else { port = 0; snprintf(ip, sizeof(ip), "IP unknown"); } // // Reset time measuring? // if (timingStatistics) { memset(&threadLastTimeStat, 0, sizeof(threadLastTimeStat)); } // // ConnectionInfo // // FIXME P1: ConnectionInfo could be a thread variable (like the static_buffer), // as long as it is properly cleaned up between calls. // We would save the call to new/free for each and every request. // Once we *really* look to scratch some efficiency, this change should be made. // // Also, is ciP->ip really used? // if ((ciP = new ConnectionInfo(url, method, version, connection)) == NULL) { LM_E(("Runtime Error (error allocating ConnectionInfo)")); return MHD_NO; } if (timingStatistics) { clock_gettime(CLOCK_REALTIME, &ciP->reqStartTime); } LM_T(LmtRequest, ("")); // WARNING: This log message below is crucial for the correct function of the Behave tests - CANNOT BE REMOVED LM_T(LmtRequest, ("--------------------- Serving request %s %s -----------------", method, url)); *con_cls = (void*) ciP; // Pointer to ConnectionInfo for subsequent calls ciP->port = port; ciP->ip = ip; ciP->callNo = reqNo; ++reqNo; // // URI parameters // // FIXME P1: We might not want to do all these assignments, they are not used in all requests ... // Once we *really* look to scratch some efficiency, this change should be made. // ciP->uriParam[URI_PARAM_PAGINATION_OFFSET] = DEFAULT_PAGINATION_OFFSET; ciP->uriParam[URI_PARAM_PAGINATION_LIMIT] = DEFAULT_PAGINATION_LIMIT; ciP->uriParam[URI_PARAM_PAGINATION_DETAILS] = DEFAULT_PAGINATION_DETAILS; MHD_get_connection_values(connection, MHD_HEADER_KIND, httpHeaderGet, &ciP->httpHeaders); char correlator[CORRELATOR_ID_SIZE + 1]; if (ciP->httpHeaders.correlator == "") { correlatorGenerate(correlator); ciP->httpHeaders.correlator = correlator; } correlatorIdSet(ciP->httpHeaders.correlator.c_str()); ciP->httpHeader.push_back("Fiware-Correlator"); ciP->httpHeaderValue.push_back(ciP->httpHeaders.correlator); // // Transaction starts here // lmTransactionStart("from", ip, port, url); // Incoming REST request starts /* X-Forwared-For (used by a potential proxy on top of Orion) overrides ip */ if (ciP->httpHeaders.xforwardedFor == "") { lmTransactionSetFrom(ip); } else { lmTransactionSetFrom(ciP->httpHeaders.xforwardedFor.c_str()); } ciP->apiVersion = apiVersionGet(ciP->url.c_str()); char tenant[SERVICE_NAME_MAX_LEN + 1]; ciP->tenantFromHttpHeader = strToLower(tenant, ciP->httpHeaders.tenant.c_str(), sizeof(tenant)); ciP->outMimeType = wantedOutputSupported(ciP->apiVersion, ciP->httpHeaders.accept, &ciP->charset); if (ciP->outMimeType == NOMIMETYPE) { ciP->outMimeType = JSON; // JSON is default output mimeType } MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, uriArgumentGet, ciP); return MHD_YES; } // // 2. Data gathering calls // // 2-1. Data gathering calls, just wait // 2-2. Last data gathering call, acknowledge the receipt of data // if (dataLen != 0) { // // If the HTTP header says the request is bigger than our PAYLOAD_MAX_SIZE, // just silently "eat" the entire message // if (ciP->httpHeaders.contentLength > PAYLOAD_MAX_SIZE) { *upload_data_size = 0; return MHD_YES; } // // First call with payload - use the thread variable "static_buffer" if possible, // otherwise allocate a bigger buffer // // FIXME P1: This could be done in "Part I" instead, saving an "if" for each "Part II" call // Once we *really* look to scratch some efficiency, this change should be made. // if (ciP->payloadSize == 0) // First call with payload { if (ciP->httpHeaders.contentLength > STATIC_BUFFER_SIZE) { ciP->payload = (char*) malloc(ciP->httpHeaders.contentLength + 1); } else { ciP->payload = static_buffer; } } // Copy the chunk LM_T(LmtPartialPayload, ("Got %d of payload of %d bytes", dataLen, ciP->httpHeaders.contentLength)); memcpy(&ciP->payload[ciP->payloadSize], upload_data, dataLen); // Add to the size of the accumulated read buffer ciP->payloadSize += *upload_data_size; // Zero-terminate the payload ciP->payload[ciP->payloadSize] = 0; // Acknowledge the data and return *upload_data_size = 0; return MHD_YES; } // // 3. Finally, serve the request (unless an error has occurred) // // URL and headers checks are delayed to the "third" MHD call, as no // errors can be sent before all the request has been read // if (urlCheck(ciP, ciP->url) == false) { alarmMgr.badInput(clientIp, "error in URI path"); restReply(ciP, ciP->answer); } ciP->servicePath = ciP->httpHeaders.servicePath; lmTransactionSetSubservice(ciP->servicePath.c_str()); if (servicePathSplit(ciP) != 0) { alarmMgr.badInput(clientIp, "error in ServicePath http-header"); restReply(ciP, ciP->answer); } if (contentTypeCheck(ciP) != 0) { alarmMgr.badInput(clientIp, "invalid mime-type in Content-Type http-header"); restReply(ciP, ciP->answer); } else if (outMimeTypeCheck(ciP) != 0) { alarmMgr.badInput(clientIp, "invalid mime-type in Accept http-header"); restReply(ciP, ciP->answer); } else { ciP->inMimeType = mimeTypeParse(ciP->httpHeaders.contentType, NULL); } if (ciP->httpStatusCode != SccOk) { alarmMgr.badInput(clientIp, "error in URI parameters"); restReply(ciP, ciP->answer); return MHD_YES; } // // Here, if the incoming request was too big, return error about it // if (ciP->httpHeaders.contentLength > PAYLOAD_MAX_SIZE) { char details[256]; snprintf(details, sizeof(details), "payload size: %d, max size supported: %d", ciP->httpHeaders.contentLength, PAYLOAD_MAX_SIZE); alarmMgr.badInput(clientIp, details); ciP->answer = restErrorReplyGet(ciP, "", ciP->url, SccRequestEntityTooLarge, details); ciP->httpStatusCode = SccRequestEntityTooLarge; } // // Requests of verb POST, PUT or PATCH are considered erroneous if no payload is present - with two exceptions. // // - Old log requests (URL contains '/log/') // - New log requests (URL is exactly '/admin/log') // if (((ciP->verb == POST) || (ciP->verb == PUT) || (ciP->verb == PATCH )) && (ciP->httpHeaders.contentLength == 0) && ((strncasecmp(ciP->url.c_str(), "/log/", 5) != 0) && (strncasecmp(ciP->url.c_str(), "/admin/log", 10) != 0))) { std::string errorMsg = restErrorReplyGet(ciP, "", url, SccContentLengthRequired, "Zero/No Content-Length in PUT/POST/PATCH request"); ciP->httpStatusCode = SccContentLengthRequired; restReply(ciP, errorMsg); alarmMgr.badInput(clientIp, errorMsg); } else if (ciP->answer != "") { alarmMgr.badInput(clientIp, ciP->answer); restReply(ciP, ciP->answer); } else { serveFunction(ciP); } return MHD_YES; }
/** * Callback function used to answer clients's connection (MHD_AccessHandlerCallback) * * @param cls Custom value selected at callback registration time, used to initialize the done flag * * @param connection The client connection * * @param url The url on which the client made its request * * @param method The http method with which the client made its request (Only GET and PUT supported) * * @param version The HTTP version string (i.e. HTTP/1.1) * * @param upload_data Data beeing uploaded when receiving PUT * * @param upload_data_size Size of the data beeing uploaded when receiving PUT * * @param con_cls reference to a pointer, initially set to NULL, that this callback can set to some * address and that will be preserved by MHD for future calls for this request * * @return MHD_YES to pursue the request handling, MHD_NO in case of error with * the request, return value of the send_* functions otherwise */ int answer_to_connection ( void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls ) { Service *requested_service; char *xmlbuff = NULL; int ret; int *done = cls; static int aptr; const char *get_arg; struct sockaddr *addr; addr = MHD_get_connection_info (connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS)->client_addr; char IP[16]; inet_ntop(addr->sa_family,addr->sa_data + 2, IP, 16); if( 0 == strcmp (method, MHD_HTTP_METHOD_GET) ) { if ( &aptr != *con_cls ) { /* do never respond on first call */ *con_cls = &aptr; return MHD_YES; } *con_cls = NULL; if( strcmp(url,"/log") == 0 ) { ret = subscribe_to_log_events(connection, con_cls, HPD_IS_UNSECURE_CONNECTION); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return ret; } else if( strcmp(url,"/events") == 0 ) { ret = set_up_server_sent_event_connection( connection, HPD_IS_UNSECURE_CONNECTION ); if( ret == MHD_HTTP_NOT_FOUND ) { Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return send_error (connection, MHD_HTTP_NOT_FOUND); } else { Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return ret; } } else if( strcmp(url,"/devices") == 0 ) { xmlbuff = get_xml_device_list(); ret = send_xml (connection, xmlbuff); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return ret; } else if( ( requested_service = matching_service (service_head, url) ) != NULL ) { get_arg = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "x"); if( get_arg != NULL ) { if( strcmp(get_arg, "1") == 0 ) { pthread_mutex_lock(requested_service->mutex); xmlbuff = extract_service_xml(requested_service); pthread_mutex_unlock(requested_service->mutex); ret = send_xml (connection, xmlbuff); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, "x=1"); return ret; } } get_arg = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "p"); if( get_arg != NULL ) { if( strcmp(get_arg, "1") == 0 ) { ret = subscribe_to_service(connection, requested_service, con_cls, HPD_IS_UNSECURE_CONNECTION); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, "p=1"); return ret; } } pthread_mutex_lock( requested_service->mutex ); ret = requested_service-> get_function( requested_service, requested_service->get_function_buffer, MHD_MAX_BUFFER_SIZE); if( ret != 0 ) requested_service->get_function_buffer[ret] = '\0'; else { pthread_mutex_unlock( requested_service->mutex ); ret = send_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return ret; } xmlbuff = get_xml_value (requested_service->get_function_buffer); pthread_mutex_unlock(requested_service->mutex); ret = send_xml(connection, xmlbuff); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return ret; } else { ret = send_error(connection, MHD_HTTP_NOT_FOUND); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return ret; } } else if( 0 == strcmp(method, MHD_HTTP_METHOD_PUT) ) { if( ( *con_cls ) == NULL ) { if( *upload_data_size == 0 ) { return MHD_YES; /* not ready yet */ } /* Add a space for a '/0' in order to clear the end of the XML */ char *put_data_temp = (char*)malloc((*upload_data_size)*sizeof(char)+1); memcpy(put_data_temp, upload_data, *upload_data_size); put_data_temp[*upload_data_size]='\0'; *con_cls = put_data_temp; *upload_data_size = 0; return MHD_YES; } else { if( ( requested_service = matching_service (service_head, url) ) !=NULL ) { pthread_mutex_lock(requested_service->mutex); if( requested_service->put_function != NULL && *con_cls != NULL ) { char* _value = get_value_from_xml_value (*con_cls); if(_value == NULL) { pthread_mutex_unlock(requested_service->mutex); ret = send_error (connection, MHD_HTTP_BAD_REQUEST); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return ret; } free(*con_cls); ret = requested_service-> put_function( requested_service, requested_service->get_function_buffer, MHD_MAX_BUFFER_SIZE, _value ); free(_value); if( ret != 0 ) requested_service->get_function_buffer[ret] = '\0'; else { pthread_mutex_unlock( requested_service->mutex ); ret = send_error(connection, MHD_HTTP_INTERNAL_SERVER_ERROR); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return ret; } xmlbuff = get_xml_value (requested_service->get_function_buffer); pthread_mutex_unlock(requested_service->mutex); send_event_of_value_change (requested_service, requested_service->get_function_buffer); ret = send_xml (connection, xmlbuff); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return ret; } else { pthread_mutex_unlock(requested_service->mutex); ret = send_error(connection, MHD_HTTP_BAD_REQUEST); Log (HPD_LOG_ONLY_REQUESTS, NULL, IP, method, url, NULL); return ret; } } else return send_error (connection, MHD_HTTP_NOT_FOUND); } } return MHD_NO; }
static int cws_response (void * cls, struct MHD_Connection * connection, const char * url, const char * method, const char * version, const char * upload_data, size_t * upload_data_size, void ** ptr) { int ret = MHD_NO; static int dummy; const char *webfile; char *page; char *basedir = ((cws_conn *) cls)->basedir; cws_astring *pathfile; struct MHD_Response *response; cws_handler *hdlr = ((cws_conn *) cls)->hdlr; const union MHD_ConnectionInfo *info; /* if (0 != strcmp(method, "GET")) return MHD_NO; */ webfile = url; if (&dummy != *ptr) { *ptr = &dummy; return MHD_YES; } *ptr = NULL; response = NULL; if (0 != *upload_data_size) { cws_handler *h = cws_handler_lookup (hdlr, webfile); if (h != NULL) { cws_dict *dict = NULL; struct MHD_PostProcessor *pp = MHD_create_post_processor(connection, 65536, post_processor, &dict); MHD_post_process(pp, upload_data, *upload_data_size); MHD_destroy_post_processor(pp); page = h->f(dict); printf("Page: %s\n", page); response = MHD_create_response_from_data (strlen (page), page, MHD_NO, MHD_YES); if (response) { printf("sending response\n"); MHD_add_response_header (response, "Content-Type", h->mimetype); ret = MHD_queue_response(connection, MHD_HTTP_OK, response); printf("if? %d\n", ret == MHD_YES ? 1 : 0); } MHD_destroy_response (response); free (page); cws_dict_free (&dict); } return MHD_NO; } info = MHD_get_connection_info (connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); log_connections (inet_ntoa(((struct sockaddr_in *) info->client_addr)->sin_addr), url); if (strcmp (webfile, "/") == 0) webfile = "/index.html"; pathfile = cws_astring_new(basedir); cws_astring_cat(pathfile, webfile); if (access (CWS_ASTRING(pathfile), F_OK) != -1) { int fd = open (CWS_ASTRING(pathfile), O_RDONLY); struct stat sbuf; fstat (fd, &sbuf); response = MHD_create_response_from_fd (sbuf.st_size, fd); MHD_add_response_header (response, "Content-Type", cws_mime_type(CWS_ASTRING(pathfile))); } else { cws_handler *h = cws_handler_lookup (hdlr, webfile); if (h != NULL) { cws_dict *dict = NULL; MHD_get_connection_values (connection, MHD_GET_ARGUMENT_KIND, get_keys, &dict); page = h->f(dict); response = MHD_create_response_from_data (strlen (page), page, MHD_NO, MHD_YES); MHD_add_response_header (response, "Content-Type", h->mimetype); free (page); cws_dict_free (&dict); } else { response = MHD_create_response_from_data (strlen (ERROR_ANSWER), ERROR_ANSWER, MHD_NO, MHD_YES); MHD_add_response_header (response, "Content-Type", cws_mime_type("html")); } } if (response != NULL) { ret = MHD_queue_response(connection, MHD_HTTP_OK, response); MHD_destroy_response (response); } cws_astring_free(pathfile); return ret; }