Esempio n. 1
0
static int
test_nested_multipart ()
{
  struct MHD_Connection connection;
  struct MHD_HTTP_Header header;
  struct MHD_PostProcessor *pp;
  unsigned int want_off = FORM_NESTED_START;
  int i;
  int delta;
  size_t size;

  memset (&connection, 0, sizeof (struct MHD_Connection));
  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
  connection.headers_received = &header;
  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
  header.value =
    MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
  header.kind = MHD_HEADER_KIND;
  pp = MHD_create_post_processor (&connection,
                                  1024, &value_checker, &want_off);
  i = 0;
  size = strlen (FORM_NESTED_DATA);
  while (i < size)
    {
      delta = 1 + MHD_random_ () % (size - i);
      MHD_post_process (pp, &FORM_NESTED_DATA[i], delta);
      i += delta;
    }
  MHD_destroy_post_processor (pp);
  if (want_off != FORM_NESTED_END)
    return 4;
  return 0;
}
Esempio n. 2
0
/**
 * Function called whenever a request was completed.
 * Used to clean up 'struct UploadContext' objects.
 *
 * @param cls client-defined closure, NULL
 * @param connection connection handle
 * @param con_cls value as set by the last call to
 *        the MHD_AccessHandlerCallback, points to NULL if this was
 *            not an upload
 * @param toe reason for request termination
 */
static void
response_completed_callback (void *cls,
			     struct MHD_Connection *connection,
			     void **con_cls,
			     enum MHD_RequestTerminationCode toe)
{
  struct UploadContext *uc = *con_cls;

  if (NULL == uc)
    return; /* this request wasn't an upload request */
  if (NULL != uc->pp)
    {
      MHD_destroy_post_processor (uc->pp);
      uc->pp = NULL;
    }
  if (-1 != uc->fd)
  {
    (void) close (uc->fd);
    if (NULL != uc->filename)
      {
	fprintf (stderr,
		 "Upload of file `%s' failed (incomplete or aborted), removing file.\n",
		 uc->filename);
	(void) unlink (uc->filename);
      }
  }
  if (NULL != uc->filename)
    free (uc->filename);
  free (uc);
}
Esempio n. 3
0
static int
test_empty_value ()
{
  struct MHD_Connection connection;
  struct MHD_HTTP_Header header;
  struct MHD_PostProcessor *pp;
  unsigned int want_off = URL_EMPTY_VALUE_START;
  int i;
  int delta;
  size_t size;

  memset (&connection, 0, sizeof (struct MHD_Connection));
  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
  connection.headers_received = &header;
  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
  header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
  header.kind = MHD_HEADER_KIND;
  pp = MHD_create_post_processor (&connection,
                                  1024, &value_checker, &want_off);
  i = 0;
  size = strlen (URL_EMPTY_VALUE_DATA);
  while (i < size)
    {
      delta = 1 + MHD_random_ () % (size - i);
      MHD_post_process (pp, &URL_EMPTY_VALUE_DATA[i], delta);
      i += delta;
    }
  MHD_destroy_post_processor (pp);
  if (want_off != URL_EMPTY_VALUE_END)
    return 8;
  return 0;
}
Esempio n. 4
0
void CWebServer::FinalizePostDataProcessing(ConnectionHandler *connectionHandler) const
{
  if (connectionHandler->postprocessor == nullptr)
    return;

  MHD_destroy_post_processor(connectionHandler->postprocessor);
}
Esempio n. 5
0
static int
test_multipart_splits ()
{
  struct MHD_Connection connection;
  struct MHD_HTTP_Header header;
  struct MHD_PostProcessor *pp;
  unsigned int want_off;
  size_t size;
  size_t splitpoint;

  size = strlen (FORM_DATA);
  for (splitpoint = 1; splitpoint < size; splitpoint++)
  {
    want_off = FORM_START;
    memset (&connection, 0, sizeof (struct MHD_Connection));
    memset (&header, 0, sizeof (struct MHD_HTTP_Header));
    connection.headers_received = &header;
    header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
    header.value =
      MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
    header.kind = MHD_HEADER_KIND;
    pp = MHD_create_post_processor (&connection,
                                    1024, &value_checker, &want_off);
    MHD_post_process (pp, FORM_DATA, splitpoint);
    MHD_post_process (pp, &FORM_DATA[splitpoint], size - splitpoint);
    MHD_destroy_post_processor (pp);
    if (want_off != FORM_END)
      return (int) splitpoint;
  }
  return 0;
}
Esempio n. 6
0
static void
completed_cb (void *cls,
	      struct MHD_Connection *connection,
	      void **con_cls,
	      enum MHD_RequestTerminationCode toe)
{
  struct MHD_PostProcessor *pp = *con_cls;

  if (NULL != pp)
    MHD_destroy_post_processor (pp);
  *con_cls = NULL;
}
Esempio n. 7
0
static void request_completed(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe)
{
	//puts("completed");
	pair *p = (pair*)*con_cls;
	if(NULL != p) {
		MHD_destroy_post_processor(p->first);
		if(p->second)
			delete p->second;
		delete p;
		*con_cls = NULL;
	}
}
Esempio n. 8
0
    int handle(Request* request, MHD_Connection* connection,
               const char* url, const char* method,
               const char* upload_data, size_t* upload_data_size) override {
        UploadContext* uc =  request->fUploadContext;

        // New connection
        if (!uc) {
            // TODO make this a method on request
            uc = new UploadContext;
            uc->connection = connection;
            uc->fPostProcessor = MHD_create_post_processor(connection, kBufferSize,
                                 &process_upload_data, uc);
            SkASSERT(uc->fPostProcessor);

            request->fUploadContext = uc;
            return MHD_YES;
        }

        // in process upload
        if (0 != *upload_data_size) {
            SkASSERT(uc->fPostProcessor);
            MHD_post_process(uc->fPostProcessor, upload_data, *upload_data_size);
            *upload_data_size = 0;
            return MHD_YES;
        }

        // end of upload
        MHD_destroy_post_processor(uc->fPostProcessor);
        uc->fPostProcessor = nullptr;

        // parse picture from stream
        request->fPicture.reset(
            SkPicture::CreateFromStream(request->fUploadContext->fStream.detachAsStream()));
        if (!request->fPicture.get()) {
            fprintf(stderr, "Could not create picture from stream.\n");
            return MHD_NO;
        }

        // pour picture into debug canvas
        request->fDebugCanvas.reset(new SkDebugCanvas(kImageWidth, kImageHeight));
        request->fDebugCanvas->drawPicture(request->fPicture);

        // clear upload context
        delete request->fUploadContext;
        request->fUploadContext = nullptr;

        return SendTemplate(connection, true, "/");
    }
Esempio n. 9
0
/**
 * Callback called upon completion of a request.
 * Decrements session reference counter.
 *
 * @param cls not used
 * @param connection connection that completed
 * @param con_cls session handle
 * @param toe status code
 */
static void
request_completed_callback (void *cls,
			    struct MHD_Connection *connection,
			    void **con_cls,
			    enum MHD_RequestTerminationCode toe)
{
  struct Request *request = *con_cls;

  if (NULL == request)
    return;
  if (NULL != request->session)
    request->session->rc--;
  if (NULL != request->pp)
    MHD_destroy_post_processor (request->pp);
  free (request);
}
Esempio n. 10
0
void request_cleanup(
		void* cls,
		struct MHD_Connection* connection,
		void** con_cls,
		enum MHD_RequestTerminationCode rtc)
{
	STATE state = *con_cls;
	if (state != NULL) {
		if (strncmp(state->method, MHD_HTTP_METHOD_POST, 25) == 0) {
			MHD_destroy_post_processor(state->processor);
			if (state->formdatalen > 0) {
				free(state->formdata);
			}
		}
		free(state);
		*con_cls = NULL;
	}
}
Esempio n. 11
0
// Callback when connection is ended
void Server::request_completed(void *cls, MHD_Connection *connection, void **con_cls, MHD_RequestTerminationCode toe){
    
    struct connection_info_struct *con_info = (connection_info_struct*)*con_cls;
    
    if (NULL == con_info) {
        return;
    }
    
    if (con_info->fConnectiontype == POST) {
        
        if (NULL != con_info->fPostprocessor) {
            MHD_destroy_post_processor(con_info->fPostprocessor);
        }
    }
    
    delete con_info;
    *con_cls = NULL;
}
Esempio n. 12
0
void HTTPServer::request_completed (void *cls, struct MHD_Connection *connection,
                   void **con_cls, enum MHD_RequestTerminationCode toe)
{
  struct connection_info_struct *con_info = (struct connection_info_struct *) *con_cls;

  if (NULL == con_info)
    return;

  if (con_info->connectiontype == POST)
    {
      MHD_destroy_post_processor (con_info->postprocessor);
      if (con_info->answerstring)
        free (con_info->answerstring);
    }

  free (con_info);
  *con_cls = NULL;
}
Esempio n. 13
0
		FUNCTION PRIVATE DEFINITION static void request_completed
			(
				void* , 
				struct MHD_Connection* , 
				void** con_cls, 
				enum MHD_RequestTerminationCode 
			)
		{
			Connection_info_struct_t* con_info = reinterpret_cast<Connection_info_struct_t*>(*con_cls);		

			if (con_info->connectiontype == POST && con_info != NULL)
			{
				MHD_destroy_post_processor(con_info->postprocessor);
				con_info->answerstring.clear();            
			}

			delete con_info;
			*con_cls = NULL;
		}    
Esempio n. 14
0
static int
ahc_echo (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 **unused)
{
  static int eok;
  struct MHD_Response *response;
  struct MHD_PostProcessor *pp;
  int ret;

  if (0 != strcmp ("POST", method))
    {
      printf ("METHOD: %s\n", method);
      return MHD_NO;            /* unexpected method */
    }
  pp = *unused;
  if (pp == NULL)
    {
      eok = 0;
      pp = MHD_create_post_processor (connection, 1024, &post_iterator, &eok);
      if (pp == NULL)
        abort ();
      *unused = pp;
    }
  MHD_post_process (pp, upload_data, *upload_data_size);
  if ((eok == 3) && (0 == *upload_data_size))
    {
      response = MHD_create_response_from_buffer (strlen (url),
						  (void *) url,
						  MHD_RESPMEM_MUST_COPY);
      ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
      MHD_destroy_response (response);
      MHD_destroy_post_processor (pp);
      *unused = NULL;
      return ret;
    }
  *upload_data_size = 0;
  return MHD_YES;
}
Esempio n. 15
0
void Webserver::Free (struct MHD_Connection *conn, void **ptr, enum MHD_RequestTerminationCode code)
{
	conninfo_t *cp = (conninfo_t *)*ptr;

	if (cp != NULL) {
		if (cp->conn_arg1 != NULL)
			free(cp->conn_arg1);
		if (cp->conn_arg2 != NULL)
			free(cp->conn_arg2);
		if (cp->conn_arg3 != NULL)
			free(cp->conn_arg3);
		if (cp->conn_arg4 != NULL)
			free(cp->conn_arg4);
		if (cp->conn_type == CON_POST) {
			MHD_destroy_post_processor(cp->conn_pp);
		}
		free(cp);
		*ptr = NULL;
	}
}
Esempio n. 16
0
File: 05.cpp Progetto: Jerryang/cdec
void MyRequestCompleted(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe)
{
	ServerContext* servctx_v = (ServerContext*)cls;
	assert(servctx_v->MagicNumber == 0xbabeface);

	ConnContext* conctx = (ConnContext*)*con_cls;
	if (conctx->PostProcessor != NULL)
	{
		puts("[POST REQUEST COMPLETED]");
		assert(conctx->Method == HTTPMETHOD_POST);
		MHD_destroy_post_processor(conctx->PostProcessor);
		conctx->KeyValueMap.clear();
	}
	else
	{
		assert(conctx->Method != HTTPMETHOD_POST);
	}

	delete conctx;
	*con_cls = NULL;   
}
Esempio n. 17
0
static int
test_multipart_garbage ()
{
  struct MHD_Connection connection;
  struct MHD_HTTP_Header header;
  struct MHD_PostProcessor *pp;
  unsigned int want_off;
  size_t size = strlen (FORM_DATA);
  size_t splitpoint;
  char xdata[size + 3];

  /* fill in evil garbage at the beginning */
  xdata[0] = '-';
  xdata[1] = 'x';
  xdata[2] = '\r';
  memcpy (&xdata[3], FORM_DATA, size);
  size += 3;

  size = strlen (FORM_DATA);
  for (splitpoint = 1; splitpoint < size; splitpoint++)
  {
    want_off = FORM_START;
    memset (&connection, 0, sizeof (struct MHD_Connection));
    memset (&header, 0, sizeof (struct MHD_HTTP_Header));
    connection.headers_received = &header;
    header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
    header.value =
      MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA ", boundary=AaB03x";
    header.kind = MHD_HEADER_KIND;
    pp = MHD_create_post_processor (&connection,
                                    1024, &value_checker, &want_off);
    MHD_post_process (pp, xdata, splitpoint);
    MHD_post_process (pp, &xdata[splitpoint], size - splitpoint);
    MHD_destroy_post_processor (pp);
    if (want_off != FORM_END)
      return (int) splitpoint;
  }
  return 0;
}
Esempio n. 18
0
static int
test_simple_large ()
{
  struct MHD_Connection connection;
  struct MHD_HTTP_Header header;
  struct MHD_PostProcessor *pp;
  int i;
  int delta;
  size_t size;
  char data[102400];
  unsigned int pos;

  pos = 0;
  memset (data, 'A', sizeof(data));
  memcpy (data, "key=", 4);
  data[sizeof(data)-1] = '\0';
  memset (&connection, 0, sizeof (struct MHD_Connection));
  memset (&header, 0, sizeof (struct MHD_HTTP_Header));
  connection.headers_received = &header;
  header.header = MHD_HTTP_HEADER_CONTENT_TYPE;
  header.value = MHD_HTTP_POST_ENCODING_FORM_URLENCODED;
  header.kind = MHD_HEADER_KIND;
  pp = MHD_create_post_processor (&connection,
                                  1024, &value_checker, &pos);
  i = 0;
  size = strlen (data);
  while (i < size)
    {
      delta = 1 + random () % (size - i);
      MHD_post_process (pp, &data[i], delta);
      i += delta;
    }
  MHD_destroy_post_processor (pp);
  if (pos != sizeof(data) - 5) /* minus 0-termination and 'key=' */
    return 1;
  return 0;
}
Esempio n. 19
0
RESTRequest::~RESTRequest()
{
    if( postProcessor )
        MHD_destroy_post_processor( postProcessor );
}
Esempio n. 20
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;
	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;

	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;
	}

	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);
					} 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);
			} 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);
		} else {
			page = MI_HTTP_U_URL;
			ret_code = MHD_HTTP_BAD_REQUEST;
		}
	}else{
		page = MI_HTTP_U_METHOD;
		ret_code = MHD_HTTP_METHOD_NOT_ACCEPTABLE;
	}

send_response:
	if (page.s) {
		LM_DBG("MHD_create_response_from_data [%p:%d]\n",
			page.s, page.len);
		response = MHD_create_response_from_data(page.len,
							(void*)page.s,
							0, 1);
	} else {
		LM_DBG("MHD_create_response_from_callback\n");
		response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN,
							buffer.len,
							cb->flush_data_callback,
							(void*)async_data,
							NULL);
	}
	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;
}
Esempio n. 21
0
int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
                      const char *url, const char *method,
                      const char *version, const char *upload_data,
                      unsigned int *upload_data_size, void **con_cls)
#endif
{
  if (cls == NULL || con_cls == NULL || *con_cls == NULL)
  {
    CLog::Log(LOGERROR, "CWebServer: invalid request received");
    return MHD_NO;
  }

  CWebServer *server = reinterpret_cast<CWebServer*>(cls);
  std::auto_ptr<ConnectionHandler> conHandler(reinterpret_cast<ConnectionHandler*>(*con_cls));
  HTTPMethod methodType = GetMethod(method);
  HTTPRequest request = { server, connection, conHandler->fullUri, url, methodType, version };

  // remember if the request was new
  bool isNewRequest = conHandler->isNew;
  // because now it isn't anymore
  conHandler->isNew = false;

  // reset con_cls and set it if still necessary
  *con_cls = NULL;

#ifdef WEBSERVER_DEBUG
  if (isNewRequest)
  {
    std::multimap<std::string, std::string> headerValues;
    GetRequestHeaderValues(connection, MHD_HEADER_KIND, headerValues);
    std::multimap<std::string, std::string> getValues;
    GetRequestHeaderValues(connection, MHD_GET_ARGUMENT_KIND, getValues);

    CLog::Log(LOGDEBUG, "webserver  [IN] %s %s %s", version, method, request.pathUrlFull.c_str());
    if (!getValues.empty())
    {
      std::string tmp;
      for (std::multimap<std::string, std::string>::const_iterator get = getValues.begin(); get != getValues.end(); ++get)
      {
        if (get != getValues.begin())
          tmp += "; ";
        tmp += get->first + " = " + get->second;
      }
      CLog::Log(LOGDEBUG, "webserver  [IN] Query arguments: %s", tmp.c_str());
    }

    for (std::multimap<std::string, std::string>::const_iterator header = headerValues.begin(); header != headerValues.end(); ++header)
      CLog::Log(LOGDEBUG, "webserver  [IN] %s: %s", header->first.c_str(), header->second.c_str());
  }
#endif

  if (!IsAuthenticated(server, connection)) 
    return AskForAuthentication(connection);

  // check if this is the first call to AnswerToConnection for this request
  if (isNewRequest)
  {
    // parse the Range header and store it in the request object
    CHttpRanges ranges;
    bool ranged = ranges.Parse(GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_RANGE));

    // look for a IHTTPRequestHandler which can take care of the current request
    for (std::vector<IHTTPRequestHandler *>::const_iterator it = m_requestHandlers.begin(); it != m_requestHandlers.end(); ++it)
    {
      IHTTPRequestHandler *requestHandler = *it;
      if (requestHandler->CanHandleRequest(request))
      {
        // we found a matching IHTTPRequestHandler so let's get a new instance for this request
        IHTTPRequestHandler *handler = requestHandler->Create(request);

        // if we got a GET request we need to check if it should be cached
        if (methodType == GET)
        {
          if (handler->CanBeCached())
          {
            bool cacheable = true;

            // handle Cache-Control
            std::string cacheControl = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CACHE_CONTROL);
            if (!cacheControl.empty())
            {
              std::vector<std::string> cacheControls = StringUtils::Split(cacheControl, ",");
              for (std::vector<std::string>::const_iterator it = cacheControls.begin(); it != cacheControls.end(); ++it)
              {
                std::string control = *it;
                control = StringUtils::Trim(control);

                // handle no-cache
                if (control.compare(HEADER_VALUE_NO_CACHE) == 0)
                  cacheable = false;
              }
            }

            if (cacheable)
            {
              // handle Pragma (but only if "Cache-Control: no-cache" hasn't been set)
              std::string pragma = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_PRAGMA);
              if (pragma.compare(HEADER_VALUE_NO_CACHE) == 0)
                cacheable = false;
            }

            CDateTime lastModified;
            if (handler->GetLastModifiedDate(lastModified) && lastModified.IsValid())
            {
              // handle If-Modified-Since or If-Unmodified-Since
              std::string ifModifiedSince = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_MODIFIED_SINCE);
              std::string ifUnmodifiedSince = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE);

              CDateTime ifModifiedSinceDate;
              CDateTime ifUnmodifiedSinceDate;
              // handle If-Modified-Since (but only if the response is cacheable)
              if (cacheable &&
                ifModifiedSinceDate.SetFromRFC1123DateTime(ifModifiedSince) &&
                lastModified.GetAsUTCDateTime() <= ifModifiedSinceDate)
              {
                struct MHD_Response *response = MHD_create_response_from_data(0, NULL, MHD_NO, MHD_NO);
                if (response == NULL)
                {
                  CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP 304 response");
                  return MHD_NO;
                }

                return FinalizeRequest(handler, MHD_HTTP_NOT_MODIFIED, response);
              }
              // handle If-Unmodified-Since
              else if (ifUnmodifiedSinceDate.SetFromRFC1123DateTime(ifUnmodifiedSince) &&
                lastModified.GetAsUTCDateTime() > ifUnmodifiedSinceDate)
                return SendErrorResponse(connection, MHD_HTTP_PRECONDITION_FAILED, methodType);
            }

            // handle If-Range header but only if the Range header is present
            if (ranged && lastModified.IsValid())
            {
              std::string ifRange = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_RANGE);
              if (!ifRange.empty() && lastModified.IsValid())
              {
                CDateTime ifRangeDate;
                ifRangeDate.SetFromRFC1123DateTime(ifRange);

                // check if the last modification is newer than the If-Range date
                // if so we have to server the whole file instead
                if (lastModified.GetAsUTCDateTime() > ifRangeDate)
                  ranges.Clear();
              }
            }

            // pass the requested ranges on to the request handler
            handler->SetRequestRanged(!ranges.IsEmpty());
          }
        }
        // if we got a POST request we need to take care of the POST data
        else if (methodType == POST)
        {
          conHandler->requestHandler = handler;

          // get the content-type of the POST data
          std::string contentType = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_TYPE);
          if (!contentType.empty())
          {
            // if the content-type is application/x-ww-form-urlencoded or multipart/form-data we can use MHD's POST processor
            if (StringUtils::EqualsNoCase(contentType, MHD_HTTP_POST_ENCODING_FORM_URLENCODED) ||
                StringUtils::EqualsNoCase(contentType, MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))
            {
              // Get a new MHD_PostProcessor
              conHandler->postprocessor = MHD_create_post_processor(connection, MAX_POST_BUFFER_SIZE, &CWebServer::HandlePostField, (void*)conHandler.get());

              // MHD doesn't seem to be able to handle this post request
              if (conHandler->postprocessor == NULL)
              {
                CLog::Log(LOGERROR, "CWebServer: unable to create HTTP POST processor for %s", url);

                delete conHandler->requestHandler;

                return SendErrorResponse(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, methodType);
              }
            }
          }

          // otherwise we need to handle the POST data ourselves which is done in the next call to AnswerToConnection
          // as ownership of the connection handler is passed to libmicrohttpd we must not destroy it 
          *con_cls = conHandler.release();

          return MHD_YES;
        }

        return HandleRequest(handler);
      }
    }
  }
  // this is a subsequent call to AnswerToConnection for this request
  else
  {
    // again we need to take special care of the POST data
    if (methodType == POST)
    {
      if (conHandler->requestHandler == NULL)
      {
        CLog::Log(LOGERROR, "CWebServer: cannot handle partial HTTP POST for %s request because there is no valid request handler available", url);
        return SendErrorResponse(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, methodType);
      }

      // we only need to handle POST data if there actually is data left to handle
      if (*upload_data_size > 0)
      {
        // either use MHD's POST processor
        if (conHandler->postprocessor != NULL)
          MHD_post_process(conHandler->postprocessor, upload_data, *upload_data_size);
        // or simply copy the data to the handler
        else
          conHandler->requestHandler->AddPostData(upload_data, *upload_data_size);

        // signal that we have handled the data
        *upload_data_size = 0;

        // we may need to handle more POST data which is done in the next call to AnswerToConnection
        // as ownership of the connection handler is passed to libmicrohttpd we must not destroy it 
        *con_cls = conHandler.release();

        return MHD_YES;
      }
      // we have handled all POST data so it's time to invoke the IHTTPRequestHandler
      else
      {
        if (conHandler->postprocessor != NULL)
          MHD_destroy_post_processor(conHandler->postprocessor);

        return HandleRequest(conHandler->requestHandler);
      }
    }
    // it's unusual to get more than one call to AnswerToConnection for none-POST requests, but let's handle it anyway
    else
    {
      for (std::vector<IHTTPRequestHandler *>::const_iterator it = m_requestHandlers.begin(); it != m_requestHandlers.end(); ++it)
      {
        IHTTPRequestHandler *requestHandler = *it;
        if (requestHandler->CanHandleRequest(request))
          return HandleRequest(requestHandler->Create(request));
      }
    }
  }

  CLog::Log(LOGERROR, "CWebServer: couldn't find any request handler for %s", url);
  return SendErrorResponse(connection, MHD_HTTP_NOT_FOUND, methodType);
}
Esempio n. 22
0
/**
 * Main MHD callback for handling requests.
 *
 *
 * @param cls argument given together with the function
 *        pointer when the handler was registered with MHD
 * @param url the requested url
 * @param method the HTTP method used ("GET", "PUT", etc.)
 * @param version the HTTP version string (i.e. "HTTP/1.1")
 * @param upload_data the data being uploaded (excluding HEADERS,
 *        for a POST that fits into memory and that is encoded
 *        with a supported encoding, the POST data will NOT be
 *        given in upload_data and is instead available as
 *        part of MHD_get_connection_values; very large POST
 *        data *will* be made available incrementally in
 *        upload_data)
 * @param upload_data_size set initially to the size of the
 *        upload_data provided; the method must update this
 *        value to the number of bytes NOT processed;
 * @param con_cls pointer that the callback can set to some
 *        address and that will be preserved by MHD for future
 *        calls for this request; since the access handler may
 *        be called many times (i.e., for a PUT/POST operation
 *        with plenty of upload data) this allows the application
 *        to easily associate some request-specific state.
 *        If necessary, this state can be cleaned up in the
 *        global "MHD_RequestCompleted" callback (which
 *        can be set with the MHD_OPTION_NOTIFY_COMPLETED).
 *        Initially, <tt>*con_cls</tt> will be NULL.
 * @return MHS_YES if the connection was handled successfully,
 *         MHS_NO if the socket must be closed due to a serios
 *         error while handling the request
 */
static int
create_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)
{
  struct MHD_Response *response;
  struct Request *request;
  struct Session *session;
  int ret;
  unsigned int i;

  request = *ptr;
  if (NULL == request)
    {
      request = calloc (1, sizeof (struct Request));
      if (NULL == request)
	{
	  fprintf (stderr, "calloc error: %s\n", strerror (errno));
	  return MHD_NO;
	}
      *ptr = request;
      if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
	{
	  request->pp = MHD_create_post_processor (connection, 1024,
						   &post_iterator, request);
	  if (NULL == request->pp)
	    {
	      fprintf (stderr, "Failed to setup post processor for `%s'\n",
		       url);
	      return MHD_NO; /* internal error */
	    }
	}
      return MHD_YES;
    }
  if (NULL == request->session)
    {
      request->session = get_session (connection);
      if (NULL == request->session)
	{
	  fprintf (stderr, "Failed to setup session for `%s'\n",
		   url);
	  return MHD_NO; /* internal error */
	}
    }
  session = request->session;
  session->start = time (NULL);
  if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
    {      
      /* evaluate POST data */
      MHD_post_process (request->pp,
			upload_data,
			*upload_data_size);
      if (0 != *upload_data_size)
	{
	  *upload_data_size = 0;
	  return MHD_YES;
	}
      /* done with POST data, serve response */
      MHD_destroy_post_processor (request->pp);
      request->pp = NULL;
      method = MHD_HTTP_METHOD_GET; /* fake 'GET' */
      if (NULL != request->post_url)
	url = request->post_url;
    }

  if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
       (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
    {
      /* find out which page to serve */
      i=0;
      while ( (pages[i].url != NULL) &&
	      (0 != strcmp (pages[i].url, url)) )
	i++;
      ret = pages[i].handler (pages[i].handler_cls, 
			      pages[i].mime,
			      session, connection);
      if (ret != MHD_YES)
	fprintf (stderr, "Failed to create page for `%s'\n",
		 url);
      return ret;
    }
  /* unsupported HTTP method */
  response = MHD_create_response_from_buffer (strlen (METHOD_ERROR),
					      (void *) METHOD_ERROR,
					      MHD_RESPMEM_PERSISTENT);
  ret = MHD_queue_response (connection, 
			    MHD_HTTP_METHOD_NOT_ACCEPTABLE, 
			    response);
  MHD_destroy_response (response);
  return ret;
}
Esempio n. 23
0
/**
 * Main callback from MHD, used to generate the page.
 *
 * @param cls NULL
 * @param connection connection handle
 * @param url requested URL
 * @param method GET, PUT, POST, etc.
 * @param version HTTP version
 * @param upload_data data from upload (PUT/POST)
 * @param upload_data_size number of bytes in "upload_data"
 * @param ptr our context
 * @return MHD_YES on success, MHD_NO to drop connection
 */
static int
generate_page (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)
{
  struct MHD_Response *response;
  int ret;
  int fd;
  struct stat buf;

  if (0 != strcmp (url, "/"))
    {
      /* should be file download */
      char file_data[MAGIC_HEADER_SIZE];
      ssize_t got;
      const char *mime;

      if ( (0 != strcmp (method, MHD_HTTP_METHOD_GET)) &&
           (0 != strcmp (method, MHD_HTTP_METHOD_HEAD)) )
        return MHD_NO;  /* unexpected method (we're not polite...) */
      if ( (0 == stat (&url[1], &buf)) &&
	   (NULL == strstr (&url[1], "..")) &&
	   ('/' != url[1]))
	fd = open (&url[1], O_RDONLY);
      else
	fd = -1;
      if (-1 == fd)
	return MHD_queue_response (connection,
				   MHD_HTTP_NOT_FOUND,
				   file_not_found_response);
      /* read beginning of the file to determine mime type  */
      got = read (fd, file_data, sizeof (file_data));
      if (-1 != got)
	mime = magic_buffer (magic, file_data, got);
      else
	mime = NULL;
      (void) lseek (fd, 0, SEEK_SET);

      if (NULL == (response = MHD_create_response_from_fd (buf.st_size,
							   fd)))
	{
	  /* internal error (i.e. out of memory) */
	  (void) close (fd);
	  return MHD_NO;
	}

      /* add mime type if we had one */
      if (NULL != mime)
	(void) MHD_add_response_header (response,
					MHD_HTTP_HEADER_CONTENT_TYPE,
					mime);
      ret = MHD_queue_response (connection,
				MHD_HTTP_OK,
				response);
      MHD_destroy_response (response);
      return ret;
    }

  if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
    {
      /* upload! */
      struct UploadContext *uc = *ptr;

      if (NULL == uc)
	{
	  if (NULL == (uc = malloc (sizeof (struct UploadContext))))
	    return MHD_NO; /* out of memory, close connection */
	  memset (uc, 0, sizeof (struct UploadContext));
          uc->fd = -1;
	  uc->connection = connection;
	  uc->pp = MHD_create_post_processor (connection,
					      64 * 1024 /* buffer size */,
					      &process_upload_data, uc);
	  if (NULL == uc->pp)
	    {
	      /* out of memory, close connection */
	      free (uc);
	      return MHD_NO;
	    }
	  *ptr = uc;
	  return MHD_YES;
	}
      if (0 != *upload_data_size)
	{
	  if (NULL == uc->response)
	    (void) MHD_post_process (uc->pp,
				     upload_data,
				     *upload_data_size);
	  *upload_data_size = 0;
	  return MHD_YES;
	}
      /* end of upload, finish it! */
      MHD_destroy_post_processor (uc->pp);
      uc->pp = NULL;
      if (-1 != uc->fd)
	{
	  close (uc->fd);
	  uc->fd = -1;
	}
      if (NULL != uc->response)
	{
	  return MHD_queue_response (connection,
				     MHD_HTTP_FORBIDDEN,
				     uc->response);
	}
      else
	{
	  update_directory ();
	  return return_directory_response (connection);
	}
    }
  if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
       (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
  {
    return return_directory_response (connection);
  }

  /* unexpected request, refuse */
  return MHD_queue_response (connection,
			     MHD_HTTP_FORBIDDEN,
			     request_refused_response);
}
Esempio n. 24
0
int WebServer::createResponse (struct MHD_Connection *connection,
                               const char *url,
                               const char *method,
                               const char *version,
                               const char *upload_data,
                               size_t *upload_data_size,
                               void **ptr)
{
    struct MHD_Response *response;
    struct Request *request;
    WebSession *session;
    int ret = MHD_NO;
    unsigned int i;
    
    request = (struct Request *)*ptr;
    if (NULL == request)
    {
        request = (struct Request *)calloc (1, sizeof (struct Request));
        if (NULL == request)
        {
            fprintf (stderr, "calloc error: %s\n", strerror (errno));
            return MHD_NO;
        }
        *ptr = request;
        if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
        {
            request->pp = MHD_create_post_processor (connection, 1024, &post_iterator, request);
            if (NULL == request->pp)
            {
                fprintf (stderr, "Failed to setup post processor for `%s'\n",
                         url);
                return MHD_NO; /* internal error */
            }
        }
        return MHD_YES;
    }
    if (NULL == request->session)
    {
        request->session = getSession(connection);
        if (NULL == request->session)
        {
            fprintf (stderr, "Failed to setup session for `%s'\n",
                     url);
            return MHD_NO; /* internal error */
        }
    }
    session = request->session;
    session->start = time (NULL);
    if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
    {
        /* evaluate POST data */
        MHD_post_process (request->pp,
                          upload_data,
                          *upload_data_size);
        /*
        if (0 != *upload_data_size)
        {
            *upload_data_size = 0;
            return MHD_YES;
        }
        */
        /* done with POST data, serve response */
        MHD_destroy_post_processor (request->pp);
        request->pp = NULL;
        method = MHD_HTTP_METHOD_GET; /* fake 'GET' */
        if (NULL != request->post_url)
            url = request->post_url;
        
        
        //handle data
        /* find out which page to serve */
        WebPage * page = NULL;
        for (auto it = _pages.begin(); it != _pages.end(); it++)
        {
            WebPage *current = *it;
            if (strcmp (current->getURL().c_str(), url) == 0)
            {
                page = current;
                break;
            }
        }
        
        if (page != NULL)
        {
            page->handlePost(session, upload_data, *upload_data_size);
        }
    }
    
    if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
        (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
    {
        /* find out which page to serve */
        WebPage * page = NULL;
        for (auto it = _pages.begin(); it != _pages.end(); it++)
        {
            WebPage *current = *it;
            if (strcmp (current->getURL().c_str(), url) == 0)
            {
                page = current;
                break;
            }
        }
        
        if (page == NULL)
        {
            page = _notFoundPage;
        }
        
        std::cout << "Serving page" << std::endl;
        
        struct MHD_Response *response;
        
        std::string replyString = page->fillRequest(session);
        // return static form
        response = MHD_create_response_from_buffer (strlen (replyString.c_str()),
                                                    (void *) replyString.c_str(),
                                                    MHD_RESPMEM_MUST_COPY);
        
        if (NULL != response)
        {
            addSessionCookie(session, response);
            MHD_add_response_header (response,
                                     MHD_HTTP_HEADER_CONTENT_ENCODING,
                                     page->getMime().c_str());
            ret = MHD_queue_response (connection,
                                      MHD_HTTP_OK,
                                      response);
            MHD_destroy_response (response);
        }
        
        /*
         
         i=0;
         while ( (pages[i].url != NULL) &&
         (0 != strcmp (pages[i].url, url)) )
         i++;
         ret = pages[i].handler (pages[i].handler_cls,
         pages[i].mime,
         session, connection);
         */
        if (ret != MHD_YES)
            fprintf (stderr, "Failed to create page for `%s'\n", url);
        return ret;
    }
    /* unsupported HTTP method */
    response = MHD_create_response_from_buffer (strlen (METHOD_ERROR),
                                                (void *) METHOD_ERROR,
                                                MHD_RESPMEM_PERSISTENT);
    ret = MHD_queue_response (connection,
                              MHD_HTTP_NOT_ACCEPTABLE,
                              response);
    MHD_destroy_response (response);
    return ret;
}
Esempio n. 25
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;
}