Exemple #1
0
// Allocation/Initialization of connection struct
connection_info_struct* Server::allocate_connection_struct(MHD_Connection *connection, const char *method){
    
    struct connection_info_struct *con_info;
    
    con_info = new connection_info_struct();
    con_info->init();
    
    if (NULL == con_info) {
        return NULL;
    }
    
    if (0 == strcmp(method, "POST")) {
        
        con_info->fPostprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE, &iterate_post, (void*)con_info);
        
        if (NULL == con_info->fPostprocessor) {
            delete con_info;
            return NULL;
        }
        
        con_info->fConnectiontype = POST;
        con_info->fAnswercode = MHD_HTTP_OK;
    } else {
        con_info->fConnectiontype = GET;
    }

    return con_info;
}
Exemple #2
0
int
RESTRequest::processUploadData( const char *upload_data, size_t upload_data_size )
{
    if( postProcessor == NULL )
    {
        postProcessor = MHD_create_post_processor( connection, POSTBUFFERSIZE, RESTRequest::iterate_post, (void *) this );
    }

    if( NULL == postProcessor )
    {
        return 0;
    }

    int result = MHD_post_process( postProcessor, upload_data, upload_data_size );

    printf( "processUploadData: %d\n", result );

    // Attempt to do form data processing.
    if( result == MHD_NO )
    {
        // The data wansn't in url-encoded form to just store it raw.
        inRepresentation.appendData( upload_data, upload_data_size );
    }

    return 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;
}
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;
}
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;
}
Exemple #6
0
void CWebServer::SetupPostDataProcessing(const HTTPRequest& request, ConnectionHandler *connectionHandler, std::shared_ptr<IHTTPRequestHandler> handler, void **con_cls) const
{
  connectionHandler->requestHandler = handler;

  // we might need to handle the POST data ourselves which is done in the next call to AnswerToConnection
  *con_cls = connectionHandler;

  // get the content-type of the POST data
  const auto contentType = HTTPRequestHandlerUtils::GetRequestHeaderValue(request.connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_TYPE);
  if (contentType.empty())
    return;

  // if the content-type is neither application/x-ww-form-urlencoded nor multipart/form-data we need to handle it ourselves
  if (!StringUtils::EqualsNoCase(contentType, MHD_HTTP_POST_ENCODING_FORM_URLENCODED) &&
      !StringUtils::EqualsNoCase(contentType, MHD_HTTP_POST_ENCODING_MULTIPART_FORMDATA))
    return;

  // otherwise we can use MHD's POST processor
  connectionHandler->postprocessor = MHD_create_post_processor(request.connection, MAX_POST_BUFFER_SIZE, &CWebServer::HandlePostField, static_cast<void*>(connectionHandler));

  // MHD doesn't seem to be able to handle this post request
  if (connectionHandler->postprocessor == nullptr)
  {
    CLog::Log(LOGERROR, "CWebServer[%hu]: unable to create HTTP POST processor for %s", m_port, request.pathUrl.c_str());
    connectionHandler->errorStatus = MHD_HTTP_INTERNAL_SERVER_ERROR;
  }
}
Exemple #7
0
dsp_server_connection_info_post::dsp_server_connection_info_post(MHD_Connection* connection):dsp_server_connection_info()
{
    fPostprocessor = 0;
    fAnswercode = MHD_HTTP_OK;
    if (!(fPostprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE, DSPServer::iteratePost, this))) {
        throw -1;
    }
}
Exemple #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, "/");
    }
/**
 * Main MHD callback for handling requests.
 *
 * @param cls unused
 * @param connection MHD connection handle
 * @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
 *        @a upload_data provided; the method must update this
 *        value to the number of bytes NOT processed;
 * @param ptr pointer to location where we store the 'struct Request'
 * @return MHD_YES if the connection was handled successfully,
 *         MHD_NO if the socket must be closed due to a serious
 *         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 GNUNET_CRYPTO_EcdsaPublicKey pub;
  int ret;

  if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
       (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
    {
      if (0 == strcmp (url, FCFS_ZONEINFO_URL))
        ret = serve_zoneinfo_page (connection);
      else
        ret = serve_main_page (connection);
      if (ret != MHD_YES)
	GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
		    _("Failed to create page for `%s'\n"),
		    url);
      return ret;
    }
  if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
    {
      request = *ptr;
      if (NULL == request)
      {
	request = GNUNET_new (struct Request);
	*ptr = request;
	request->pp = MHD_create_post_processor (connection, 1024,
						 &post_iterator, request);
	if (NULL == request->pp)
	  {
	    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
			_("Failed to setup post processor for `%s'\n"),
			url);
	    return MHD_NO; /* internal error */
	  }
	return MHD_YES;
      }
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;
}
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;
}
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;
}
Exemple #13
0
		FUNCTION PRIVATE DEFINITION static 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
			)
		{
			#ifdef DEBUG
				std::printf("%s %s %s\n", version, method, url);
			#endif        
			Str_t smethod(method);    
			if (*con_cls == NULL)
			{
				Connection_info_struct_t* con_info = new (VAR2STR(Connection_info_struct_t)) Connection_info_struct_t;        
				if (con_info == NULL) return MHD_NO;
				con_info->answerstring.clear();

				if (smethod.compare(txPOST) == 0)
				{
					con_info->postprocessor = MHD_create_post_processor(connection, POST_BUFFER_SIZE, iterate_post, (void *) con_info);
					if (con_info->postprocessor == NULL)
					{
						#ifdef DEBUG                    
							std::printf("[ERROR-LOG][deploy::answer_to_connection] POST Request not datas to process.\n");
						#endif                    
						delete con_info;
						return MHD_NO;
					}
					con_info->connectiontype = POST;
				}
				else if (smethod.compare(txGET) == 0)	
				{
					con_info->connectiontype = GET;			
				}

				*con_cls = (void *) con_info;

				return MHD_YES;
			}

			if (smethod.compare(txGET) == 0)
			{
				Str_t page, mimetype;
				page_dispatcher(Str_t(url), page, mimetype);
				return send_page (connection, page, mimetype);
			}

			if (smethod.compare(txPOST) == 0)
			{
				Connection_info_struct_t* con_info = reinterpret_cast<Connection_info_struct_t*>(*con_cls);

				if (*upload_data_size != 0)
				{
					MHD_post_process (con_info->postprocessor, upload_data, *upload_data_size);
					*upload_data_size = 0;
		            
					return MHD_YES;
				}
				else if (!con_info->post_key_value.empty())
				{     				
					
				}
			}
			Str_t page, mimetype;
			deployapp::page_dispatcher("", page, mimetype);
			return send_page (connection, page, mimetype); 	
		}    
Exemple #14
0
int ahc_echo(void* servctx, MHD_Connection* connection, const char* url, const char* method, const char* version, const char* upload_data, size_t* upload_data_size, void** reqctx)
{
	ServerContext* servctx_v = (ServerContext*)servctx;
	assert(servctx_v->MagicNumber == 0xbabeface);

	if (*reqctx == NULL)
	{
		assert(upload_data == NULL && *upload_data_size == 0);
		ConnContext* conctx = new ConnContext();
		if (strcmp(method, MHD_HTTP_METHOD_GET) == 0)
		{
			conctx->Method = HTTPMETHOD_GET;
			conctx->PostProcessor = NULL;
		}
		else if (strcmp(method, MHD_HTTP_METHOD_POST) == 0)
		{
			conctx->Method = HTTPMETHOD_POST;
			conctx->PostProcessor = MHD_create_post_processor(connection, 1024, MyPostDataIterator, conctx);
		}
		else
			return MHD_NO;		

		// The first time only the headers are valid, do not respond in the first round.
		*reqctx = conctx;
		return MHD_YES;
	}
	else
	{
		ConnContext* conctx = (ConnContext*)(*reqctx);
		if (conctx->Method == HTTPMETHOD_GET)
		{
			assert(strcmp(method, MHD_HTTP_METHOD_GET) == 0);
			assert(*upload_data_size == 0);

			MHD_Response* response = MHD_create_response_from_buffer(sizeof(HELLO_MESSAGE), (void*)HELLO_MESSAGE, MHD_RESPMEM_PERSISTENT);
			MHD_add_response_header(response, "Content-Type", "text/html");
			int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
			MHD_destroy_response(response);

			// Do not call "*reqctx = NULL;" because a request completed callback would be called instead
			return ret;
		}
		else if (conctx->Method == HTTPMETHOD_POST)
		{
			if (*upload_data_size != 0)
			{
				MHD_post_process (conctx->PostProcessor, upload_data, *upload_data_size);
				*upload_data_size = 0;
          
				return MHD_YES;
			}
			else
			{
				puts("[POST COMPLETE]");

				std::string message = "<html><body>\n<p>POST</p>\n<ul>\n";
				for (std::map<std::string, std::string>::iterator it = conctx->KeyValueMap.begin(); it != conctx->KeyValueMap.end(); ++it)
				{
					message += "<li>"; message += it->first; message += '='; message += it->second;
					message += "</li>\n";
				}
				message += "</ul>\n</body></html>\n";

				MHD_Response* response = MHD_create_response_from_buffer(message.size(), (void*)message.c_str(), MHD_RESPMEM_MUST_COPY);
				MHD_add_response_header(response, "Content-Type", "text/html");
				int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
				MHD_destroy_response(response);

				// Do not call "*reqctx = NULL;" because a request completed callback would be called instead
				return ret;
			}
		}
		else
			return MHD_NO;
	}
}
Exemple #15
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;
}
Exemple #16
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;
}
/**
 * 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;
}
Exemple #18
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);
}
int Webserver::Handler (struct MHD_Connection *conn, const char *url,
		const char *method, const char *version, const char *up_data,
		size_t *up_data_size, void **ptr)
{
	int ret;
	conninfo_t *cp;

	if (debug)
		fprintf(stderr, "%x: %s: \"%s\" conn=%x size=%d *ptr=%x\n", pthread_self(), method, url, conn, *up_data_size, *ptr);

    // add by zp
    //const char *encoding = MHD_lookup_connection_value (conn,
    //                                      MHD_HEADER_KIND,
    //                                      MHD_HTTP_HEADER_CONTENT_TYPE);
    //fprintf(stderr,"encoding: %s\n",encoding);

	if (*ptr == NULL) {	/* do never respond on first call */
		cp = (conninfo_t *)malloc(sizeof(conninfo_t));
		if (cp == NULL)
			return MHD_NO;
		cp->conn_url = url;
		cp->conn_arg1 = NULL;
		cp->conn_arg2 = NULL;
		cp->conn_arg3 = NULL;
		cp->conn_arg4 = NULL;
		cp->conn_res = NULL;
		if (strcmp(method, MHD_HTTP_METHOD_POST) == 0) {
			cp->conn_pp = MHD_create_post_processor(conn, 1024, web_config_post, (void *)cp);
        // add by zp 
        fprintf(stderr,"cp->conn_pp is %x\n",cp->conn_pp);
			if (cp->conn_pp == NULL) {
				free(cp);
				return MHD_NO;
			}
			cp->conn_type = CON_POST;
		} else if (strcmp(method, MHD_HTTP_METHOD_GET) == 0) {
			cp->conn_type = CON_GET;
		} else {
			free(cp);
			return MHD_NO;
		}
		*ptr = (void *)cp;
		return MHD_YES;
	}
	if (strcmp(method, MHD_HTTP_METHOD_GET) == 0) {
        // add by zp
        fprintf(stderr,"----------Get url:%s\n",url);
		if (strcmp(url, "/") == 0)
			ret = web_send_file(conn, "templates/advertisement.html", MHD_HTTP_OK, false);
		else if(strcmp(url, "/index") == 0)
			ret = web_send_file(conn, "templates/index.html", MHD_HTTP_OK, false);
		else if(strcmp(url, "/index.js") == 0)
			ret = web_send_file(conn, "templates/index.js", MHD_HTTP_OK, false);
		else if(strcmp(url, "/moive/big_buck_bunny") == 0)
			ret = web_send_file(conn, "moive/big_buck_bunny.ogv", MHD_HTTP_OK, false);
		else if(strcmp(url, "/poll") == 0){
			ret = SendPollResponse(conn);
            //char *page = (char *)malloc(256);
            //sprintf(page,"<html><head><title>poll data</title></head><body>receive data:%d</body></html>\n",mydata->get_data());

            //ret = web_send_data(conn,page,MHD_HTTP_OK,true,false,NULL);
        }




		else if(strcmp(url, "/css/uikit.min.css") == 0)
			ret = web_send_file(conn, "css/uikit.min.css", MHD_HTTP_OK, false);
		else if(strcmp(url, "/css/progress.min.css") == 0)
			ret = web_send_file(conn, "css/progress.min.css", MHD_HTTP_OK, false);
		else if(strcmp(url, "/js/jquery.js") == 0)
			ret = web_send_file(conn, "js/jquery.js", MHD_HTTP_OK, false);
		else if(strcmp(url, "/js/uikit.min.js") == 0)
			ret = web_send_file(conn, "js/uikit.min.js", MHD_HTTP_OK, false);
		else
			ret = web_send_data(conn, UNKNOWN, MHD_HTTP_NOT_FOUND, false, false, NULL); // no free, no copy
		return ret;
	} else if (strcmp(method, MHD_HTTP_METHOD_POST) == 0) {
        // add by zp
        fprintf(stderr,"----------Post url:%s \n",url);
		cp = (conninfo_t *)*ptr;

		if ( 0 == strcmp(url, "/index") ) {
            if (*up_data_size != 0) {
                MHD_post_process(cp->conn_pp, up_data, *up_data_size);
                *up_data_size = 0;

                return MHD_YES;
            } else
			    ret = web_send_file(conn, "templates/index.html", MHD_HTTP_OK, false);
		} 
        else if( 0 == strcmp(url,"/startapp") ){
            printf("up_data_size:%d\n",*up_data_size);
            if (*up_data_size != 0) {
                // add
                printf("before MHD_post_process\n");
                MHD_post_process(cp->conn_pp, up_data, *up_data_size);
                printf("after MHD_post_process\n");
                *up_data_size = 0;

                mydata->set_data((char *)cp->conn_arg1);
                //printf("func:%s,line:%s,startdata:%d\n",__func__,__LINE__,cp->conn_arg1);
                return MHD_YES;
            } else
                ret = web_send_data(conn, EMPTY, MHD_HTTP_OK, false, false, NULL); // no free, no copy

        }
        else
			ret = web_send_data(conn, UNKNOWN, MHD_HTTP_NOT_FOUND, false, false, NULL); // no free, no copy
		return ret;
	} else
    return MHD_NO;
}
/**
 * A client has requested the given url using the given method
 * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
 * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc).  The callback
 * must call MHD callbacks to provide content to give back to the
 * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
 * #MHD_HTTP_NOT_FOUND, etc.).
 *
 * @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 (#MHD_HTTP_METHOD_GET,
 *        #MHD_HTTP_METHOD_PUT, etc.)
 * @param version the HTTP version string (i.e.
 *        #MHD_HTTP_VERSION_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
 *        @a upload_data)
 * @param upload_data_size set initially to the size of the
 *        @a 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_RequestCompletedCallback (which
 *        can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
 *        Initially, `*con_cls` will be NULL.
 * @return #MHD_YES if the connection was handled successfully,
 *         #MHD_NO if the socket must be closed due to a serios
 *         error while handling the request
 */
static 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)
{
    if (*con_cls == NULL) {
        printf("CON_CLS is NULL. Request-type: %s\n", method);

        struct connection_info_struct *con_info;

        con_info = malloc(sizeof(struct connection_info_struct));
        if (con_info == NULL) {
            return MHD_NO;
        }
        con_info->answerstring = NULL;

        if (strcmp(method, "POST") == 0) {
            con_info->postprocessor = MHD_create_post_processor(connection, POSTBUFFERSIZE, iterate_post, (void *) con_info);

            if (con_info->postprocessor == NULL) {
                free(con_info);
                return MHD_NO;
            }

            con_info->connectiontype = POST;
        } else if (strcmp(method, "DELETE") == 0) {
            con_info->connectiontype = DELETE;
        } else {
            con_info->connectiontype = GET;
        }

        *con_cls = (void *) con_info;

        return MHD_YES;
    }

    printf("CON_CLS is NOT NULL.\n");

    if (0 == strcmp(method, "GET")) {
        char modifiableUrl [strlen(url) + 1];
        strncpy(modifiableUrl, url, sizeof modifiableUrl);
        modifiableUrl[strlen(url)] = '\0';
        char * argument = strtok(modifiableUrl, "/"); // remove api name
        argument = strtok(NULL, "/");
        int parsedArgument = atoi(argument);

        int responseValue = hashGet(parsedArgument);

        if (responseValue >= 0) {
          char buffer[100]; // totally arbitrary but pretty big
          sprintf(buffer, "200 - OK\nValue: %d\n", responseValue);
          return send_page(connection, MHD_HTTP_OK, buffer);
        } else if (responseValue == NOT_FOUND) {
          return send_page(connection, 404, "404 - Not found\nThere are no entries matching your key.\n");
        } else {
          return send_page(connection, 500, "500 - Internal server error\n");
        }
    }

    if (0 == strcmp(method, "DELETE")) {
        printf("DELETE REQUEST to %s >>>\n", url);
        char modifiableUrl [strlen(url) + 1];
        strncpy(modifiableUrl, url, sizeof modifiableUrl);
        modifiableUrl[strlen(url)] = '\0';
        char * argument = strtok(modifiableUrl, "/"); // remove api name
        argument = strtok(NULL, "/");
        int parsedArgument = atoi(argument);
        printf("Parsed as %d from %s\n", parsedArgument, argument);

        int responseValue = hashDel(parsedArgument);
        printf("Result: %d\n", responseValue);
        if (responseValue >= 0) {
          return send_page(connection, 200, "200 - OK\n");
        } else if (responseValue == NOT_FOUND) {
          return send_page(connection, 404, "404 - Not found\nThere are no entries matching your key.\n");
        } else {
          return send_page(connection, 500, "500 - Internal server error\n");
        }
    }

    if (0 == strcmp(method, "POST")) {
        struct connection_info_struct *con_info = *con_cls;

        if (*upload_data_size != 0) {
            MHD_post_process(con_info->postprocessor, upload_data, *upload_data_size);

            *upload_data_size = 0;

            return MHD_YES;
        } else if (keySet && valueSet) {
            keySet = 0;
            valueSet = 0;

            printf("Set %d:%d!\n", key, value);
            if (hashSet(key, value)) {
              const char *responseText = "201 - Created\n";

              struct MHD_Response *response = MHD_create_response_from_buffer(strlen(responseText), (void*) responseText, MHD_RESPMEM_PERSISTENT);

              char buffer[100]; // totally arbitrary but pretty big
              sprintf(buffer, "http://localhost:%d%s/%d", port, url, key);

              MHD_add_response_header (response, "Location", buffer);
              int ret = MHD_queue_response (connection, 201, response);
              MHD_destroy_response(response);

              return MHD_YES;
            } else {
              return send_page(connection, 500, "500 - Internal server error\n");
            }
        } else {
            return send_page(connection, MHD_HTTP_BAD_REQUEST, "400 - Malformed request\n");
        }
    }

    return send_page(connection, MHD_HTTP_NOT_FOUND, "404 - Not found\n");
}
Exemple #21
0
static 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)
{
	struct connection_info_struct *con_info = *con_cls;

  //printf("method =%s \n",method);
  if (NULL == *con_cls)
    {
    	//printf("NuLl=ClS \n");
		
      struct connection_info_struct *con_info;

      con_info = malloc (sizeof (struct connection_info_struct));
      if (NULL == con_info)
        return MHD_NO;
      con_info->answerstring = NULL;

      if (0 == strcmp (method, "POST"))
        {
          con_info->postprocessor =
            MHD_create_post_processor (connection, POSTBUFFERSIZE,
                                       iterate_post, (void *) con_info);

          if (NULL == con_info->postprocessor)
            {
              free (con_info);
              return MHD_NO;
            }

          con_info->connectiontype = POST;
        }
      else
        con_info->connectiontype = GET;

      *con_cls = (void *) con_info;

      return MHD_YES;
    }

  if (0 == strcmp (method, "GET"))
    {
    	char *reply;
    	reply = malloc (strlen (askpage) + strlen (str) + 1);
	  	if (NULL == reply)
	    	return MHD_NO;
	  	snprintf (reply,strlen (askpage) + strlen (str) + 1,askpage,str);
		return send_page (connection,reply);
    }

  if (0 == strcmp (method, "POST"))
  	{  		
	  int ret;
	  //char *reply;
	  //char *str = "open";
	  //printf("PoSt \n");
	  //struct MHD_Response *response;
	  
	  //reply = malloc (strlen (askpage) + strlen (str) + 1); 
	  //if (NULL == reply)
	  //  return MHD_NO;
	  //snprintf (reply,strlen (askpage) + strlen (str) + 1,askpage,str);
	  //printf("reply= %s \n",reply);
	  //struct connection_info_struct *con_info = *con_cls;

	  if (*upload_data_size != 0)
	  {
		MHD_post_process (con_info->postprocessor, upload_data,
						  *upload_data_size);
		*upload_data_size = 0;

		return MHD_YES;
	  }
	  else if (NULL != con_info->answerstring)
		  return send_page (connection, con_info->answerstring);

	  
  	}

  return send_page (connection, errorpage);
}
Exemple #22
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);
}
Exemple #23
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;
}
Exemple #24
0
int HTTPServer::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)
{
	Logging::getInstance()->Log(Logging::INFO, "answering a connection: %s , %s, %s", url, method, upload_data);

  if (NULL == *con_cls)
    {
      struct connection_info_struct *con_info;

      con_info = (struct connection_info_struct *) malloc (sizeof (struct connection_info_struct));
      if (NULL == con_info)
        return MHD_NO;
      con_info->answerstring = NULL;

      if (0 == strcmp (method, "POST"))
        {
          con_info->postprocessor =
            MHD_create_post_processor (connection, POSTBUFFERSIZE,
                                       iterate_post, (void *) con_info);

          if (NULL == con_info->postprocessor)
            {
              free (con_info);
              return MHD_NO;
            }

          con_info->connectiontype = POST;
        }
      else
        con_info->connectiontype = GET;

      *con_cls = (void *) con_info;

      return MHD_YES;
    }

  if (0 == strcmp (method, "GET"))
    {
      return send_page (connection, askpage);
    }

  if (0 == strcmp (method, "POST"))
    {
      struct connection_info_struct *con_info = (struct connection_info_struct *) *con_cls;

      if (*upload_data_size != 0)
        {
          Logging::getInstance()->Log(Logging::INFO, "Just received a data stream with content:\n%s\n", upload_data);

          std::string rxed_string(upload_data);
          JsonObject rxed_json;
          if(JsonObject::ParseFromString(rxed_string, rxed_json)){
        	  unsigned long curr_time = current_date_time_msec();
        	  long delay_time = -1;
        	  if(rxed_json.hasValue("tx_time")){
            	  unsigned long tx_time = rxed_json.GetUInt("tx_time");
            	  delay_time = (long) curr_time - (long) tx_time;
        	  }
        	  rxed_json.PutUInt("rx_time",current_date_time_msec());
        	  rxed_json.PutInt("delay_time",delay_time);
              Logging::getInstance()->Log(Logging::INFO, "Just received a json message with content:\n%s\n", rxed_json.ToString().c_str());
              //Add to Message Queue

              GetMessageQueue()->pushToEnd(rxed_json);

          }else{
        	  //Data Stream is not JSON formatted

          }

          MHD_post_process (con_info->postprocessor, upload_data,
                            *upload_data_size);
          *upload_data_size = 0;

          return MHD_YES;
        }
      else if (NULL != con_info->answerstring)
        return send_page (connection, con_info->answerstring);
    }

  return send_page (connection, errorpage);
}
Exemple #25
0
static int server_handler(
	void *cls, struct MHD_Connection *connection, const char *url, const char *method,
	const char *version, const char *upload_data, size_t *upload_size, void **con_cls) 
{
	if(NULL == *con_cls) { //first time, read header
		//puts("first");
		//printf("%s %s\n", method, url);

		if(strcmp(method, "GET") == 0) {
			char *result;
			applog(url);
			if(strstr(url, "/query_") == url) { 
				if(result=JUDGE_get_progress(url)) {
					struct MHD_Response *response = 
						MHD_create_response_from_buffer(strlen(result), result, MHD_RESPMEM_MUST_FREE);
					// MHD_add_response_header(response, "Connection", "close");
					int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
					MHD_destroy_response(response);
					return ret;
				}
			}else if(strcmp(url, "/robots.txt") == 0) {
				struct MHD_Response *response = 
					MHD_create_response_from_buffer(sizeof(robots_txt)-1, robots_txt, MHD_RESPMEM_PERSISTENT);
				// MHD_add_response_header(response, "Connection", "close");
				int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
				MHD_destroy_response(response);
				return ret;
			}
			return ignore_requst(connection);
		}
		if(strcmp(method, "POST") == 0 && strcmp(url, "/submit_prob") == 0) {
			//puts("accept");

			pair *p = new pair;
			if(NULL == p)
				return MHD_NO;
			*con_cls = p;

			solution *body = new solution;
			if(NULL == body)
				return MHD_NO;
			p->second = body;
			
			MHD_PostProcessor *processor 
				= MHD_create_post_processor(connection, 768, iterate_post, (void*)p);
			if(NULL == processor)
				return MHD_NO;
			p->first = processor;
			//puts("success");
			return MHD_YES;
		}
		return ignore_requst(connection);
	}else{
		pair *p = (pair*)*con_cls;
		if(0 != *upload_size) { //next, read body
#ifdef DUMP_FOR_DEBUG
			p->second->raw_post_data += upload_data;
#endif
			MHD_post_process(p->first, upload_data, *upload_size);
			*upload_size = 0;
			//puts("next");
			return MHD_YES;
		}else{ //last time, finish reading
			//puts("last");
			char *result;
			if(p->second->type == TYPE_rejudge)
				result = JUDGE_start_rejudge(p->second);
			else
				result = JUDGE_accept_submit(p->second);
			struct MHD_Response *response = 
				MHD_create_response_from_buffer(strlen(result), result, MHD_RESPMEM_MUST_FREE);
			int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
			MHD_destroy_response(response);
			return ret;
		}
	}
}