Example #1
0
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;
}
Example #2
0
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);
}
Example #3
0
/*
 * 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;
}
Example #4
0
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;
}
Example #5
0
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
    );
}
Example #6
0
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
}
Example #7
0
/**
 * @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;
}
Example #8
0
/* ****************************************************************************
*
* 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;
}
Example #9
0
// 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;
    }
}
Example #10
0
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;
}
Example #11
0
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;
}
Example #12
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)
  {
    //
    // 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;
}
Example #14
0
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;
}