Beispiel #1
0
void WebProcessor::Dispatch()
{
	if (*m_szUrl != '/')
	{
		SendErrorResponse(ERR_HTTP_BAD_REQUEST);
		return;
	}

	if (XmlRpcProcessor::IsRpcRequest(m_szUrl))
	{
		XmlRpcProcessor processor;
		processor.SetRequest(m_szRequest);
		processor.SetHttpMethod(m_eHttpMethod == hmGet ? XmlRpcProcessor::hmGet : XmlRpcProcessor::hmPost);
		processor.SetUserAccess((XmlRpcProcessor::EUserAccess)m_eUserAccess);
		processor.SetUrl(m_szUrl);
		processor.Execute();
		SendBodyResponse(processor.GetResponse(), strlen(processor.GetResponse()), processor.GetContentType()); 
		return;
	}

	if (Util::EmptyStr(g_pOptions->GetWebDir()))
	{
		SendErrorResponse(ERR_HTTP_SERVICE_UNAVAILABLE);
		return;
	}
	
	if (m_eHttpMethod != hmGet)
	{
		SendErrorResponse(ERR_HTTP_BAD_REQUEST);
		return;
	}
	
	// for security reasons we allow only characters "0..9 A..Z a..z . - _ /" in the URLs
	// we also don't allow ".." in the URLs
	for (char *p = m_szUrl; *p; p++)
	{
		if (!((*p >= '0' && *p <= '9') || (*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
			*p == '.' || *p == '-' || *p == '_' || *p == '/') || (*p == '.' && p[1] == '.'))
		{
			SendErrorResponse(ERR_HTTP_NOT_FOUND);
			return;
		}
	}

	const char *szDefRes = "";
	if (m_szUrl[strlen(m_szUrl)-1] == '/')
	{
		// default file in directory (if not specified) is "index.html"
		szDefRes = "index.html";
	}

	char disk_filename[1024];
	snprintf(disk_filename, sizeof(disk_filename), "%s%s%s", g_pOptions->GetWebDir(), m_szUrl + 1, szDefRes);

	disk_filename[sizeof(disk_filename)-1] = '\0';

	SendFileResponse(disk_filename);
}
Beispiel #2
0
int CWebServer::CreateMemoryDownloadResponse(IHTTPRequestHandler *handler, struct MHD_Response *&response)
{
  if (handler == NULL)
    return MHD_NO;

  const HTTPRequest &request = handler->GetRequest();
  const HTTPResponseDetails &responseDetails = handler->GetResponseDetails();
  HttpResponseRanges responseRanges = handler->GetResponseData();

  // check if the response is completely empty
  if (responseRanges.empty())
    return CreateMemoryDownloadResponse(request.connection, NULL, 0, false, false, response);

  // check if the response contains more ranges than the request asked for
  if ((request.ranges.IsEmpty() && responseRanges.size() > 1) ||
     (!request.ranges.IsEmpty() && responseRanges.size() > request.ranges.Size()))
  {
    CLog::Log(LOGWARNING, "CWebServer: response contains more ranges (%d) than the request asked for (%d)", (int)responseRanges.size(), (int)request.ranges.Size());
    return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
  }

  // if the request asked for no or only one range we can simply use MHDs memory download handler
  // we MUST NOT send a multipart response
  if (request.ranges.Size() <= 1)
  {
    CHttpResponseRange responseRange = responseRanges.front();
    // check if the range is valid
    if (!responseRange.IsValid())
    {
      CLog::Log(LOGWARNING, "CWebServer: invalid response data with range start at %" PRId64 " and end at %" PRId64, responseRange.GetFirstPosition(), responseRange.GetLastPosition());
      return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
    }

    const void* responseData = responseRange.GetData();
    size_t responseDataLength = static_cast<size_t>(responseRange.GetLength());

    switch (responseDetails.type)
    {
    case HTTPMemoryDownloadNoFreeNoCopy:
      return CreateMemoryDownloadResponse(request.connection, responseData, responseDataLength, false, false, response);

    case HTTPMemoryDownloadNoFreeCopy:
      return CreateMemoryDownloadResponse(request.connection, responseData, responseDataLength, false, true, response);

    case HTTPMemoryDownloadFreeNoCopy:
      return CreateMemoryDownloadResponse(request.connection, responseData, responseDataLength, true, false, response);

    case HTTPMemoryDownloadFreeCopy:
      return CreateMemoryDownloadResponse(request.connection, responseData, responseDataLength, true, true, response);

    default:
      return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
    }
  }

  return CreateRangedMemoryDownloadResponse(handler, response);
}
Beispiel #3
0
int CWebServer::HandleRequest(IHTTPRequestHandler *handler)
{
  if (handler == NULL)
    return MHD_NO;

  HTTPRequest request = handler->GetRequest();
  int ret = handler->HandleRequest();
  if (ret == MHD_NO)
  {
    CLog::Log(LOGERROR, "CWebServer: failed to handle HTTP request for %s", request.pathUrl.c_str());
    delete handler;
    return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
  }

  const HTTPResponseDetails &responseDetails = handler->GetResponseDetails();
  struct MHD_Response *response = NULL;
  switch (responseDetails.type)
  {
    case HTTPNone:
      CLog::Log(LOGERROR, "CWebServer: HTTP request handler didn't process %s", request.pathUrl.c_str());
      delete handler;
      return MHD_NO;

    case HTTPRedirect:
      ret = CreateRedirect(request.connection, handler->GetRedirectUrl(), response);
      break;

    case HTTPFileDownload:
      ret = CreateFileDownloadResponse(handler, response);
      break;

    case HTTPMemoryDownloadNoFreeNoCopy:
    case HTTPMemoryDownloadNoFreeCopy:
    case HTTPMemoryDownloadFreeNoCopy:
    case HTTPMemoryDownloadFreeCopy:
      ret = CreateMemoryDownloadResponse(handler, response);
      break;

    case HTTPError:
      ret = CreateErrorResponse(request.connection, responseDetails.status, request.method, response);
      break;

    default:
      CLog::Log(LOGERROR, "CWebServer: internal error while HTTP request handler processed %s", request.pathUrl.c_str());
      delete handler;
      return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
  }

  if (ret == MHD_NO)
  {
    CLog::Log(LOGERROR, "CWebServer: failed to create HTTP response for %s", request.pathUrl.c_str());
    delete handler;
    return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
  }

  return FinalizeRequest(handler, responseDetails.status, response);
}
Beispiel #4
0
/*
 * Stream contains open file descriptors that could not be completed.
 * If stream has only pending open file descriptors close file
 * descriptors.
 */
static void
closeStream()
{
	FileInfo_t *file;
	int id;

	id = Stream->first;
	while (id > EOS) {
		PthreadMutexLock(&Stream->mutex);
		file = GetFile(id);
		PthreadMutexLock(&file->mutex);
		if (GET_FLAG(file->flags, FI_DCACHE_CLOSE)) {
			if (close(file->dcache) == -1) {
				WarnSyscallError(HERE,
				    "close", "");
			}
			CLEAR_FLAG(file->flags, FI_DCACHE);
			NumOpenFiles--;

		} else if (GET_FLAG(file->flags, FI_DCACHE)) {
			SendErrorResponse(file);
		}

		id = file->next;
		PthreadMutexUnlock(&Stream->mutex);
		PthreadMutexUnlock(&file->mutex);
	}

	if (GET_FLAG(Stream->flags, SR_UNAVAIL)) {
		rejectRequest(ENODEV, B_TRUE);
	} else {
		rejectRequest(0, B_TRUE);
	}
}
Beispiel #5
0
/*
 * Remove file with dcache opened from stream.
 * Caller must have the stream lock held.
 */
static void
removeDcachedFile(
	StreamInfo_t *stream,
	int error)
{
	int id;
	FileInfo_t *file, *prev = NULL;

	id = stream->first;
	while (id > EOS) {
		boolean_t removed = B_FALSE;

		file = GetFile(id);
		PthreadMutexLock(&file->mutex);

		if (prev != NULL) {
			PthreadMutexLock(&prev->mutex);
		}
		if (GET_FLAG(file->flags, FI_DCACHE)) {
			/*
			 * Remove file from stream.
			 * If multivolume and not section 0, set ECOMM to not
			 * retry from another copy.
			 */
			if (file->ar[file->copy].ext_ord != 0 ||
			    file->se_ord != 0) {
				file->error = ECOMM;
			} else {
				file->error = error;
			}
			SendErrorResponse(file);

			if (prev != NULL) {
				prev->next = file->next;
			} else {
				stream->first = file->next;
			}
			stream->count--;
			if (stream->first == EOS) {
				stream->last = EOS;
			} else if (file->sort == stream->last) {
				ASSERT(prev != NULL);
				stream->last = prev->sort;
			}
			removed = B_TRUE;
		}
		if (prev != NULL) {
			PthreadMutexUnlock(&prev->mutex);
		}
		PthreadMutexUnlock(&file->mutex);
		id = file->next;
		if (removed) {
			SetStageDone(file);
		} else {
			prev = file;
		}
	}
}
void CTcTestRunner::BearerCompletion( MTcBearerObserver::TOperation aOp,
									  TInt aStatus )
	{
	// If we get an error from the bearer, "recommend" disconnect to the AppUi :-)
	// (usually the only error is KErrDisconnected)
	if( aStatus != KErrNone )
		{
		iObserver.NotifyDisconnect();
		return;
		}

	switch( aOp )
		{
		case MTcBearerObserver::ESend:
			{
			// Clear buffers
			iResponse.Zero();
			iRequest.Zero();
			// Start receiving data again
			Start();
			break;
			}
		case MTcBearerObserver::EReceive:
			{
			// Update request data length (add new data).
			iRequest.SetLength( iRequest.Length() + iFreeRequest.Length() );
			// Do we have a complete request in iRequest?
			if( !iCodec.IsComplete() )
				{
				// No, read more
				Start();
				}
			else
				{
				// Yes, try to execute the request
				TRAPD( err, ExecuteL() );
				// Report any errors
				if( err )
					{
					SendErrorResponse( err );
					}
				iCurrentRequest.Zero();
				iObserver.NotifyStatusChange();
				}
			break;
			}
		default:
			{
			// does not happen, ignored
			break;
			}
		}
	}
EXPORT_C void CTcTestRunner::Start()
	{
	// Is there still room in the receive buffer?
	if( iRequest.Length() < iRequest.MaxLength() )
		{
		// Construct a pointer descriptor for the free data area of iRequest
		// This is done to accomplish "appending" socket read.
		TInt dataLen( iRequest.Length() );
		iFreeRequest.Set( const_cast< TUint8* >( iRequest.Ptr() ) + dataLen, 0,
						  iRequest.MaxLength() - dataLen );
		iBearer.ReceiveOneOrMore( iFreeRequest );
		}
	else
		{
		SendErrorResponse( KTcErrReceiveOverflow );
		}
	}
Beispiel #8
0
void WebProcessor::SendFileResponse(const char* filename)
{
	debug("serving file: %s", filename);

	CharBuffer body;
	if (!FileSystem::LoadFileIntoBuffer(filename, body, false))
	{
		// do not print warnings "404 not found" for certain files
		bool ignorable = !strcmp(filename, "package-info.json") ||
			!strcmp(filename, "favicon.ico") ||
			!strncmp(filename, "apple-touch-icon", 16);

		SendErrorResponse(ERR_HTTP_NOT_FOUND, ignorable);
		return;
	}

	SendBodyResponse(body, body.Size(), DetectContentType(filename));
}
Beispiel #9
0
void WebProcessor::SendFileResponse(const char* szFilename)
{
	debug("serving file: %s", szFilename);

	char *szBody;
	int iBodyLen;
	if (!Util::LoadFileIntoBuffer(szFilename, &szBody, &iBodyLen))
	{
		SendErrorResponse(ERR_HTTP_NOT_FOUND);
		return;
	}
	
	// "LoadFileIntoBuffer" adds a trailing NULL, which we don't need here
	iBodyLen--;
	
	SendBodyResponse(szBody, iBodyLen, DetectContentType(szFilename));

	free(szBody);
}
Beispiel #10
0
int CWebServer::CreateFileDownloadResponse(IHTTPRequestHandler *handler, struct MHD_Response *&response)
{
  if (handler == NULL)
    return MHD_NO;

  const HTTPRequest &request = handler->GetRequest();
  const HTTPResponseDetails &responseDetails = handler->GetResponseDetails();
  HttpResponseRanges responseRanges = handler->GetResponseData();

  std::shared_ptr<XFILE::CFile> file = std::make_shared<XFILE::CFile>();
  std::string filePath = handler->GetResponseFile();

  if (!file->Open(filePath, READ_NO_CACHE))
  {
    CLog::Log(LOGERROR, "WebServer: Failed to open %s", filePath.c_str());
    return SendErrorResponse(request.connection, MHD_HTTP_NOT_FOUND, request.method);
  }

  bool ranged = false;
  uint64_t fileLength = static_cast<uint64_t>(file->GetLength());

  // get the MIME type for the Content-Type header
  std::string mimeType = responseDetails.contentType;
  if (mimeType.empty())
  {
    std::string ext = URIUtils::GetExtension(filePath);
    StringUtils::ToLower(ext);
    mimeType = CreateMimeTypeFromExtension(ext.c_str());
  }

  if (request.method != HEAD)
  {
    uint64_t totalLength = 0;
    std::unique_ptr<HttpFileDownloadContext> context(new HttpFileDownloadContext());
    context->file = file;
    context->contentType = mimeType;
    context->boundaryWritten = false;
    context->writePosition = 0;

    if (handler->IsRequestRanged())
    {
      if (!request.ranges.IsEmpty())
        context->ranges = request.ranges;
      else
        GetRequestedRanges(request.connection, fileLength, context->ranges);
    }

    uint64_t firstPosition = 0;
    uint64_t lastPosition = 0;
    // if there are no ranges, add the whole range
    if (context->ranges.IsEmpty())
      context->ranges.Add(CHttpRange(0, fileLength - 1));
    else
    {
      handler->SetResponseStatus(MHD_HTTP_PARTIAL_CONTENT);

      // we need to remember that we are ranged because the range length might change and won't be reliable anymore for length comparisons
      ranged = true;

      context->ranges.GetFirstPosition(firstPosition);
      context->ranges.GetLastPosition(lastPosition);
    }

    // remember the total number of ranges
    context->rangeCountTotal = context->ranges.Size();
    // remember the total length
    totalLength = context->ranges.GetLength();

    // adjust the MIME type and range length in case of multiple ranges which requires multipart boundaries
    if (context->rangeCountTotal > 1)
    {
      context->boundary = HttpRangeUtils::GenerateMultipartBoundary();
      mimeType = HttpRangeUtils::GenerateMultipartBoundaryContentType(context->boundary);

      // build part of the boundary with the optional Content-Type header
      // "--<boundary>\r\nContent-Type: <content-type>\r\n
      context->boundaryWithHeader = HttpRangeUtils::GenerateMultipartBoundaryWithHeader(context->boundary, context->contentType);
      context->boundaryEnd = HttpRangeUtils::GenerateMultipartBoundaryEnd(context->boundary);

      // for every range, we need to add a boundary with header
      for (HttpRanges::const_iterator range = context->ranges.Begin(); range != context->ranges.End(); ++range)
      {
        // we need to temporarily add the Content-Range header to the boundary to be able to determine the length
        std::string completeBoundaryWithHeader = HttpRangeUtils::GenerateMultipartBoundaryWithHeader(context->boundaryWithHeader, &*range);
        totalLength += completeBoundaryWithHeader.size();

        // add a newline before any new multipart boundary
        if (range != context->ranges.Begin())
          totalLength += strlen(HEADER_NEWLINE);
      }
      // and at the very end a special end-boundary "\r\n--<boundary>--"
      totalLength += context->boundaryEnd.size();
    }

    // set the initial write position
    context->ranges.GetFirstPosition(context->writePosition);

    // create the response object
    response = MHD_create_response_from_callback(totalLength, 2048,
                                                  &CWebServer::ContentReaderCallback,
                                                  context.get(),
                                                  &CWebServer::ContentReaderFreeCallback);
    if (response == NULL)
    {
      CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP response for %s to be filled from %s", request.pathUrl.c_str(), filePath.c_str());
      return MHD_NO;
    }

    context.release(); // ownership was passed to mhd

    // add Content-Range header
    if (ranged)
      handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_RANGE, HttpRangeUtils::GenerateContentRangeHeaderValue(firstPosition, lastPosition, fileLength));
  }
  else
  {
    response = MHD_create_response_from_data(0, NULL, MHD_NO, MHD_NO);
    if (response == NULL)
    {
      CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP HEAD response for %s", request.pathUrl.c_str());
      return MHD_NO;
    }

    handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_LENGTH, StringUtils::Format("%" PRId64, fileLength));
  }

  // set the Content-Type header
  if (!mimeType.empty())
    handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_TYPE, mimeType);

  return MHD_YES;
}
Beispiel #11
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);
}
Beispiel #12
0
// Read a command from the CRS
uint8_t ReadCmd(void) {
	Command Cmd;
	uint32_t *NewNodeNames;
	pEdgeArray NewEdges;
	uint32_t i;
	pNode NewNode;
	pEdge NewEdge;
	pEdge ExistingEdge;
	uint8_t NodeCount;
	uint32_t *SPT;

	// read in the basic command header
	if (ReadBytes((unsigned char *)&Cmd, sizeof(Command)) != sizeof(Command)) {
		return(0);
	}

	if (Cmd.Action == CMD_SEND_NODES) {
		// read in the indicated number of Nodes
#ifdef PATCHED_1
		if ((Cmd.NumElements + NumNodes) > MAX_NODES) {
#else
		if (Cmd.NumElements > MAX_NODES) {
#endif
			ReadNull(sizeof(uint32_t)*Cmd.NumElements);
			SendErrorResponse(RESP_ERROR_TOO_MANY_NODES);
			return(0);
		}
		if ((NewNodeNames = (uint32_t *)calloc(sizeof(uint32_t)*Cmd.NumElements)) == NULL) {
			DestroyNodes();
			DestroyEdges();
			_terminate(1);
		}
		if (ReadBytes((unsigned char *)NewNodeNames, sizeof(uint32_t)*Cmd.NumElements) != sizeof(uint32_t)*Cmd.NumElements) {
			free(NewNodeNames);
			return(0);
		}

		// make sure none of the new node names exist already
		for (i = 0; i < Cmd.NumElements; i++) {
			if (FindNode(NewNodeNames[i]) != NULL) {
				free(NewNodeNames);
				SendErrorResponse(RESP_ERROR_DUPLICATE_NODE);
				return(0);
			}
		}

		// Create the new nodes 
		for (i = 0; i < Cmd.NumElements; i++) {
			// create a new node
			if ((NewNode = (pNode)calloc(sizeof(Node))) == NULL) {
				free(NewNodeNames);
				DestroyNodes();
				DestroyEdges();
				_terminate(1);
			}
			NewNode->Name = NewNodeNames[i];
			NewNode->Distance = SIZE_MAX;
			// Add it to the graph
			if (!AddNode(NewNode)) {
				free(NewNodeNames);
				DestroyNodes();
				DestroyEdges();
				_terminate(1);
			}
		}

		// done creating new nodes
		free(NewNodeNames);

	} else if (Cmd.Action == CMD_SEND_EDGES) {
		// read in the indicated number of Edges
		if ((Cmd.NumElements + NumEdges) > MAX_EDGES) {
			ReadNull(sizeof(EdgeArray)*Cmd.NumElements);
			SendErrorResponse(RESP_ERROR_TOO_MANY_EDGES);
			return(0);
		}
		if ((NewEdges = (pEdgeArray)calloc(sizeof(EdgeArray)*Cmd.NumElements)) == NULL) {
			DestroyNodes();
			DestroyEdges();
			_terminate(1);
		}
		if (ReadBytes((unsigned char *)NewEdges, sizeof(EdgeArray)*Cmd.NumElements) != sizeof(EdgeArray)*Cmd.NumElements) {
			free(NewEdges);
			return(0);
		}
		
		// Create the new edges 
		for (i = 0; i < Cmd.NumElements; i++) {
			// create a new Edge
			if ((NewEdge = (pEdge)calloc(sizeof(Edge))) == NULL) {
				free(NewEdges);
				DestroyNodes();
				DestroyEdges();
				_terminate(1);
			}
			// make sure the starting and ending nodes exist
			if ((NewEdge->NodeA = FindNode(NewEdges[i].NodeA)) == NULL) {
				SendErrorResponse(RESP_ERROR_INVALID_NODE);
				free(NewEdge);
				free(NewEdges);
				DestroyNodes();
				DestroyEdges();
				_terminate(1);
			}
			if ((NewEdge->NodeZ = FindNode(NewEdges[i].NodeZ)) == NULL) {
				SendErrorResponse(RESP_ERROR_INVALID_NODE);
				free(NewEdge);
				free(NewEdges);
				DestroyNodes();
				DestroyEdges();
				_terminate(1);
			}
			// offset the weight by a fixed magic_page-based value
			NewEdge->Weight = NewEdges[i].Weight + rand_page[NumNodes];

			// see if one already exists
			if ((ExistingEdge = FindEdge(NewEdge->NodeA, NewEdge->NodeZ)) != NULL) {
				if (ExistingEdge->Weight > NewEdge->Weight) {
					ExistingEdge->Weight = NewEdge->Weight;
				}

				// keep the existing edge
				free(NewEdge);
				continue;
			}

			// Add it to the graph
			if (!AddEdge(NewEdge)) {
				free(NewEdge);
				free(NewEdges);
				DestroyNodes();
				DestroyEdges();
				_terminate(1);
			}
		}

	} else if (Cmd.Action == CMD_RUN_SPT) {
		if ((SPT = FindSpt(Cmd.StartingNode, Cmd.EndingNode, &NodeCount)) == NULL) {
			// unable to find SPT
			SendErrorResponse(RESP_ERROR_SPT_FAIL);
			return(0);
		}
		SendResponse(RESP_NODE_SET, NodeCount, SPT);
		free(SPT);

	} else {
		SendErrorResponse(RESP_ERROR_INVALID_CMD);
		return(0);
	}

	return(1);
}
Beispiel #13
0
/*******************************************************************************
* Function Name: ProcessWriteReq
********************************************************************************
*
* Summary:
*  Process all GATT level write requests and responds with appropriate status
*
* Parameters:
*  CYBLE_GATTS_WRITE_CMD_REQ_PARAM_T:  GATT write command request prameter
*
* Return:
*  None
*
*******************************************************************************/
void ProcessWriteReq(CYBLE_GATTS_WRITE_CMD_REQ_PARAM_T writeCmdReq)
{
    bool value_val;
    uint8 status = LOCKED, key_buf[LOCK_CODE_LENGTH];
    uint16 beaconPeriod = 0;
    CYBLE_GATT_HANDLE_VALUE_PAIR_T valuePairT;
    /* Reset error send flag */
    errorSent = false;
    /* Retrieve the LOCK status from the GATT DB */
    valuePairT.attrHandle =
                        CYBLE_EDDYSTONE_CONFIGURATION_LOCK_STATE_CHAR_HANDLE;
    valuePairT.value.val = (uint8 *)&value_val;
    valuePairT.value.len = sizeof(bool);

    CyBle_GattsReadAttributeValue( &valuePairT, &cyBle_connHandle,
                                    CYBLE_GATT_DB_LOCALLY_INITIATED );

    /* Check the LOCK status */
    if(valuePairT.value.val[0] == UNLOCKED)
    {
        /*URL Data*/
        if(writeCmdReq.handleValPair.attrHandle ==
                            CYBLE_EDDYSTONE_CONFIGURATION_URI_DATA_CHAR_HANDLE)
        {
            /* First byte should be scheme prefix and length should be less than
            *  or equal to MAX_URL_LENGTH */
            if( (writeCmdReq.handleValPair.value.len <= MAX_URL_LENGTH) &&
                (writeCmdReq.handleValPair.value.val[0] < URL_PREFIX_MAX)   )
            {
                uint8 TempURL[MAX_URL_LENGTH];
                memset(TempURL, 0, MAX_URL_LENGTH);
                memcpy(
                            TempURL,
                            writeCmdReq.handleValPair.value.val,
                            writeCmdReq.handleValPair.value.len
                       );
                if( CYBLE_GATT_ERR_NONE == WriteAttributeValue   (
                            CYBLE_EDDYSTONE_CONFIGURATION_URI_DATA_CHAR_HANDLE,
                            writeCmdReq.handleValPair.value.len,
                            writeCmdReq.handleValPair.value.val,
                            CYBLE_GATT_DB_PEER_INITIATED        ) )
                {
                    /* Update the length as per the new URL data */
                    URLLength = writeCmdReq.handleValPair.value.len;
                    cyBle_attValuesLen[16].actualLength = URLLength;
                    /* Update the URL data */
                    memcpy(CurrentURL, TempURL, MAX_URL_LENGTH);
                }
            }
            else if (writeCmdReq.handleValPair.value.len > MAX_URL_LENGTH)
            {
                 /* Invalid length. Send error response */
               SendErrorResponse        (
                            CYBLE_EDDYSTONE_CONFIGURATION_URI_DATA_CHAR_HANDLE,
                            CYBLE_GATT_ERR_INVALID_ATTRIBUTE_LEN
                                        );
            }
        }
        /* Lock Characteristic */
        else if(writeCmdReq.handleValPair.attrHandle ==
                                CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE)
        {

            if(writeCmdReq.handleValPair.value.len == LOCK_CODE_LENGTH)
            {
                WriteAttributeValue (
                                CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE,
                                writeCmdReq.handleValPair.value.len,
                                writeCmdReq.handleValPair.value.val,
                                CYBLE_GATT_DB_PEER_INITIATED
                                    );

                /* Update the LOCK characteristic */
                status = LOCKED;
                WriteAttributeValue (
                        CYBLE_EDDYSTONE_CONFIGURATION_LOCK_STATE_CHAR_HANDLE,
                        sizeof(bool), &status,
                        CYBLE_GATT_DB_LOCALLY_INITIATED
                                    );
            }
            else
            {
                /* Invalid length. Send error response */
               SendErrorResponse(CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE,
                                    CYBLE_GATT_ERR_INVALID_ATTRIBUTE_LEN);
            }
        }
        /* Advertised Tx power level */
        else if(writeCmdReq.handleValPair.attrHandle ==
           CYBLE_EDDYSTONE_CONFIGURATION_ADVERTISED_TX_POWER_LEVELS_CHAR_HANDLE)
        {

            if (writeCmdReq.handleValPair.value.len == MAX_NUM_PWR_LVL)
            {
                WriteAttributeValue (
                    CYBLE_EDDYSTONE_CONFIGURATION_ADVERTISED_TX_POWER_LEVELS_CHAR_HANDLE,
                    writeCmdReq.handleValPair.value.len,
                    writeCmdReq.handleValPair.value.val,
                    CYBLE_GATT_DB_PEER_INITIATED
                                    );

                if (writeCmdReq.handleValPair.value.len == MAX_NUM_PWR_LVL)
                {
                    /* Update Tx Power levels */
                    memcpy  (
                                currentTxPowerLevels,
                                writeCmdReq.handleValPair.value.val,
                                MAX_NUM_PWR_LVL
                            );
                }
                else
                {
                    SendErrorResponse   (
                        CYBLE_EDDYSTONE_CONFIGURATION_ADVERTISED_TX_POWER_LEVELS_CHAR_HANDLE,
                        CYBLE_GATT_ERR_INVALID_ATTRIBUTE_LEN
                                        );
                }
            }
            else
            {
                /* Invalid length. Send error response */
               SendErrorResponse    (
                    CYBLE_EDDYSTONE_CONFIGURATION_ADVERTISED_TX_POWER_LEVELS_CHAR_HANDLE,
                    CYBLE_GATT_ERR_INVALID_ATTRIBUTE_LEN
                                    );
            }
        }
        /* Tx Power Mode */
        else if(writeCmdReq.handleValPair.attrHandle ==
                        CYBLE_EDDYSTONE_CONFIGURATION_TX_POWER_MODE_CHAR_HANDLE)
        {

            if(writeCmdReq.handleValPair.value.val[0] <= 0x03)
            {
                WriteAttributeValue (
                        CYBLE_EDDYSTONE_CONFIGURATION_TX_POWER_MODE_CHAR_HANDLE,
                        writeCmdReq.handleValPair.value.len,
                        writeCmdReq.handleValPair.value.val,
                        CYBLE_GATT_DB_PEER_INITIATED
                                    );
                currentTxmode = writeCmdReq.handleValPair.value.val[0];

                UpdateTxPower(currentTxmode);
            }
            else /* Invalid value. Write not permitted. */
            {
                SendErrorResponse   (
                        CYBLE_EDDYSTONE_CONFIGURATION_TX_POWER_MODE_CHAR_HANDLE,
                        CYBLE_GATT_ERR_WRITE_NOT_PERMITTED
                                    );
            }
        }
        /* Beacon Period */
        else if(writeCmdReq.handleValPair.attrHandle ==
                        CYBLE_EDDYSTONE_CONFIGURATION_BEACON_PERIOD_CHAR_HANDLE)
        {

            beaconPeriod =
                        CyBle_Get16ByPtr(writeCmdReq.handleValPair.value.val);

            /* Disable URL FRAMES */
            if(beaconPeriod == 0)
            {
                eddystoneImplenmentation = EDDYSTONE_UID;
                WriteAttributeValue (
                        CYBLE_EDDYSTONE_CONFIGURATION_BEACON_PERIOD_CHAR_HANDLE,
                        writeCmdReq.handleValPair.value.len,
                        writeCmdReq.handleValPair.value.val,
                        CYBLE_GATT_DB_PEER_INITIATED
                                    );
            }
            /* Values in valid range */
            else if((beaconPeriod >= MIN_BEACON_PERIOD) &&
                    (beaconPeriod <= MAX_BEACON_PERIOD))
            {
                WriteAttributeValue (
                        CYBLE_EDDYSTONE_CONFIGURATION_BEACON_PERIOD_CHAR_HANDLE,
                        writeCmdReq.handleValPair.value.len,
                        writeCmdReq.handleValPair.value.val,
                        CYBLE_GATT_DB_PEER_INITIATED
                                    );
                CurrentAdvPeriod = beaconPeriod / 0.625;
                eddystoneImplenmentation = EDDYSTONE_URL;
            }
            else
            {
                uint16 temp = MIN_BEACON_PERIOD;
                /* Values not supportes. Write default values */
                WriteAttributeValue(
                        CYBLE_EDDYSTONE_CONFIGURATION_BEACON_PERIOD_CHAR_HANDLE,
                        sizeof(temp),
                        (uint8 *)&temp,
                        CYBLE_GATT_DB_PEER_INITIATED);
                CurrentAdvPeriod = CYBLE_GAP_ADV_ADVERT_INTERVAL_NONCON_MIN;
                eddystoneImplenmentation = EDDYSTONE_URL;
            }
        }
        /* Reset the Configurations to default */
        else if((writeCmdReq.handleValPair.attrHandle ==
                CYBLE_EDDYSTONE_CONFIGURATION_RESET_CHAR_HANDLE) &&
                (writeCmdReq.handleValPair.value.val[0] != 0))

        {
            ResetGattDb();
        }
    }
    else if(valuePairT.value.val[0] == LOCKED)
    {

        if(writeCmdReq.handleValPair.attrHandle ==
                                CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE)
        {
            /* Accesing the lock in LOCKED state */
            SendErrorResponse(writeCmdReq.handleValPair.attrHandle,
                                    CYBLE_GATT_ERR_INSUFFICIENT_AUTHORIZATION);
        }
    }

    if(writeCmdReq.handleValPair.attrHandle ==
                        CYBLE_EDDYSTONE_CONFIGURATION_UNLOCK_CHAR_HANDLE)
    {
        if(writeCmdReq.handleValPair.value.len == LOCK_CODE_LENGTH)
        {
            if(valuePairT.value.val[0] == LOCKED)
            {
                int compareResult;
                valuePairT.attrHandle =
                                CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE;
                valuePairT.value.val = key_buf;
                valuePairT.value.len = sizeof(LOCK);
                CyBle_GattsReadAttributeValue(&valuePairT, &cyBle_connHandle,
                                            CYBLE_GATT_DB_LOCALLY_INITIATED);

                compareResult = memcmp  (
                                            valuePairT.value.val,
                                            writeCmdReq.handleValPair.value.val,
                                            LOCK_CODE_LENGTH
                                        );

                if(compareResult == 0)
                {
                    status = UNLOCKED;
                    /* Update the LOCK STATE */
                    WriteAttributeValue (
                        CYBLE_EDDYSTONE_CONFIGURATION_LOCK_STATE_CHAR_HANDLE,
                        sizeof(bool), &status,
                        CYBLE_GATT_DB_LOCALLY_INITIATED
                                        );

                    /* Reset the LOCK */
                    WriteAttributeValue (
                                CYBLE_EDDYSTONE_CONFIGURATION_LOCK_CHAR_HANDLE,
                                sizeof(LOCK), (uint8 *)LOCK,
                                CYBLE_GATT_DB_LOCALLY_INITIATED
                                        );
                }
                else /* LOCK not matched */
                {
                    SendErrorResponse(writeCmdReq.handleValPair.attrHandle,
                                    CYBLE_GATT_ERR_INSUFFICIENT_AUTHORIZATION);
                }
            }
        }
        else /* Invalid length */
        {
            SendErrorResponse(writeCmdReq.handleValPair.attrHandle,
                                        CYBLE_GATT_ERR_INVALID_ATTRIBUTE_LEN);
        }
    }

    if (errorSent == false)
    {
        CyBle_GattsWriteRsp(cyBle_connHandle);
    }
}
Beispiel #14
0
int CWebServer::HandlePartialRequest(struct MHD_Connection *connection, ConnectionHandler* connectionHandler, const HTTPRequest& request, const char *upload_data, size_t *upload_data_size, void **con_cls)
{
  std::unique_ptr<ConnectionHandler> conHandler(connectionHandler);

  // 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 = nullptr;

  if (!IsAuthenticated(request))
    return AskForAuthentication(request);

  // check if this is the first call to AnswerToConnection for this request
  if (isNewRequest)
  {
    // look for a IHTTPRequestHandler which can take care of the current request
    auto handler = FindRequestHandler(request);
    if (handler != nullptr)
    {
      // if we got a GET request we need to check if it should be cached
      if (request.method == GET)
      {
        if (handler->CanBeCached())
        {
          bool cacheable = IsRequestCacheable(request);

          CDateTime lastModified;
          if (handler->GetLastModifiedDate(lastModified) && lastModified.IsValid())
          {
            // handle If-Modified-Since or If-Unmodified-Since
            std::string ifModifiedSince = HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_MODIFIED_SINCE);
            std::string ifUnmodifiedSince = HTTPRequestHandlerUtils::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 = create_response(0, nullptr, MHD_NO, MHD_NO);
              if (response == nullptr)
              {
                CLog::Log(LOGERROR, "CWebServer[%hu]: failed to create a HTTP 304 response", m_port);
                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(request, MHD_HTTP_PRECONDITION_FAILED, request.method);
          }

          // pass the requested ranges on to the request handler
          handler->SetRequestRanged(IsRequestRanged(request, lastModified));
        }
      }
      // if we got a POST request we need to take care of the POST data
      else if (request.method == POST)
      {
        // as ownership of the connection handler is passed to libmicrohttpd we must not destroy it
        SetupPostDataProcessing(request, conHandler.get(), handler, con_cls);

        // as ownership of the connection handler has been passed to libmicrohttpd we must not destroy it
        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 (request.method == POST)
    {
      // process additional / remaining POST data
      if (ProcessPostData(request, conHandler.get(), upload_data, upload_data_size, con_cls))
      {
        // as ownership of the connection handler has been passed to libmicrohttpd we must not destroy it
        conHandler.release();

        return MHD_YES;
      }

      // finalize POST data processing
      FinalizePostDataProcessing(conHandler.get());

      // check if something went wrong while handling the POST data
      if (conHandler->errorStatus != MHD_HTTP_OK)
        return SendErrorResponse(request, conHandler->errorStatus, request.method);

      // we have handled all POST data so it's time to invoke the IHTTPRequestHandler
      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
    auto requestHandler = FindRequestHandler(request);
    if (requestHandler != nullptr)
      return HandleRequest(requestHandler);
  }

  CLog::Log(LOGERROR, "CWebServer[%hu]: couldn't find any request handler for %s", m_port, request.pathUrl.c_str());
  return SendErrorResponse(request, MHD_HTTP_NOT_FOUND, request.method);
}
void CStunThreadMessageHandler::ProcessRequest(StunMessageEnvelope& message)
{
    CStunMessageReader reader;
    CStunMessageReader::ReaderParseState state;
    uint16_t responsePort = 0;
    HRESULT hr = S_OK;


    ChkIfA(_spStunResponder == NULL, E_FAIL);

    _spReaderBuffer->SetSize(0);
    _spResponseBuffer->SetSize(0);
    _message = message;

    _addrResponse = message.remoteAddr;
    _socketOutput = message.localSocket;
    _fRequestHasResponsePort = false;
    
    // zero out _error without the overhead of zero'ing out every byte in the strings
    _error.errorcode = 0;
    _error.szNonce[0] = 0;
    _error.szRealm[0] = 0;
    _error.attribUnknown = 0;
    
    _integrity.fSendWithIntegrity = false;
    _integrity.szUser[0] = '\0';
    _integrity.szRealm[0] = '\0';
    _integrity.szPassword[0] = '\0';
    
    
    // attach the temp buffer to reader
    reader.GetStream().Attach(_spReaderBuffer, true);


    reader.SetAllowLegacyFormat(true);

    // parse the request
    state = reader.AddBytes(message.spBuffer->GetData(), message.spBuffer->GetSize());

    // If we get something that can't be validated as a stun message, don't send back a response
    // STUN RFC may suggest sending back a "500", but I think that's the wrong approach.
    ChkIf (state != CStunMessageReader::BodyValidated, E_FAIL);
    
    // Regardless of what we send back, let's always attempt to honor a response port request
    // Fix the destination port if the client asked for us to send back to another port
    if (SUCCEEDED(reader.GetResponsePort(&responsePort)))
    {
        _addrResponse.SetPort(responsePort);
        _fRequestHasResponsePort = true;
    }

    reader.GetTransactionId(&_transid);

    // ignore anything that is not a request (with no response)
    ChkIf(reader.GetMessageClass() != StunMsgClassRequest, E_FAIL);

    // pre-prep the error message in case we wind up needing to send it
    _error.msgtype = reader.GetMessageType();
    _error.msgclass = StunMsgClassFailureResponse;

    if (reader.GetMessageType() != StunMsgTypeBinding)
    {
        // we're going to send back an error response
        _error.errorcode = STUN_ERROR_BADREQUEST; // invalid request
    }
    else
    {
        // handle authentication - but only if an auth provider has been set
        hr = ValidateAuth(reader);

        // if auth succeeded, then carry on to handling the request
        if (SUCCEEDED(hr) && (_error.errorcode==0))
        {
            // handle the binding request
            hr = ProcessBindingRequest(reader);
        }

        // catch all for any case where an error occurred
        if (FAILED(hr) && (_error.errorcode==0))
        {
            _error.errorcode = STUN_ERROR_BADREQUEST;
        }
    }

    if (_error.errorcode != 0)
    {
        // if either ValidateAuth or ProcessBindingRequest set an errorcode, or a fatal error occurred
        SendErrorResponse();
    }
    else
    {
        SendResponse();
    }


Cleanup:
    return;
}
Beispiel #16
0
// The Simple Query Protocol
// Fix mis-split bug: Previously, this function assumes there are multiple
// queries in the string and split it by ';', which would cause one containing
// ';' being split into multiple queries.
// However, the multi-statement queries has been split by the psql client and
// there is no need to split the query again.
void PacketManager::ExecQueryMessage(InputPacket *pkt, const size_t thread_id) {
  std::string query;
  PacketGetString(pkt, pkt->len, query);

  // pop out the last character if it is ';'
  if (query.back() == ';') {
    query.pop_back();
  }
  boost::trim(query);

  if (!query.empty()) {
    std::vector<StatementResult> result;
    std::vector<FieldInfo> tuple_descriptor;
    std::string error_message;
    int rows_affected = 0;

    std::string query_type_string_;
    Statement::ParseQueryTypeString(query, query_type_string_);

    QueryType query_type;
    Statement::MapToQueryType(query_type_string_, query_type);
    std::stringstream stream(query_type_string_);

    switch (query_type) {
      case QueryType::QUERY_PREPARE:
      {
        std::string statement_name;
        stream >> statement_name;
        std::size_t pos = query.find("AS");
        std::string statement_query = query.substr(pos + 3);
        boost::trim(statement_query);

        // Prepare statement
        std::shared_ptr<Statement> statement(nullptr);

        LOG_DEBUG("PrepareStatement[%s] => %s", statement_name.c_str(),
                statement_query.c_str());

        statement = traffic_cop_->PrepareStatement(statement_name, statement_query,
                                                 error_message);
        if (statement.get() == nullptr) {
          skipped_stmt_ = true;
          SendErrorResponse(
              {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}});
          LOG_TRACE("ExecQuery Error");
          return;
        }

        auto entry = std::make_pair(statement_name, statement);
        statement_cache_.insert(entry);
        for (auto table_id : statement->GetReferencedTables()) {
          table_statement_cache_[table_id].push_back(statement.get());
        }
        break;
      }
      case QueryType::QUERY_EXECUTE:
      {
        std::string statement_name;
        std::shared_ptr<Statement> statement;
        std::vector<type::Value> param_values;
        bool unnamed = false;
        std::vector<std::string> tokens;

        boost::split(tokens, query, boost::is_any_of("(), "));

        statement_name = tokens.at(1);
        auto statement_cache_itr = statement_cache_.find(statement_name);
        if (statement_cache_itr != statement_cache_.end()) {
          statement = *statement_cache_itr;
        }
        // Did not find statement with same name
        else {
          std::string error_message = "The prepared statement does not exist";
          LOG_ERROR("%s", error_message.c_str());
          SendErrorResponse(
              {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}});
          SendReadyForQuery(NetworkTransactionStateType::IDLE);
          return;
        }

        std::vector<int> result_format(statement->GetTupleDescriptor().size(), 0);

        for (std::size_t idx = 2; idx < tokens.size(); idx++) {
          std::string param_str = tokens.at(idx);
          boost::trim(param_str);
          if (param_str.empty()) {
            continue;
          }
          param_values.push_back(type::ValueFactory::GetVarcharValue(param_str));
        }

        if (param_values.size() > 0) {
          statement->GetPlanTree()->SetParameterValues(&param_values);
        }

        auto status =
                traffic_cop_->ExecuteStatement(statement, param_values, unnamed, nullptr, result_format,
                             result, rows_affected, error_message, thread_id);

        if (status == ResultType::SUCCESS) {
          tuple_descriptor = statement->GetTupleDescriptor();
        } else {
          SendErrorResponse(
                {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}});
          SendReadyForQuery(NetworkTransactionStateType::IDLE);
          return;
        }
      	break;
      }
      default:
      {
        // execute the query using tcop
        auto status = traffic_cop_->ExecuteStatement(
            query, result, tuple_descriptor, rows_affected, error_message,
            thread_id);

      // check status
        if (status == ResultType::FAILURE) {
          SendErrorResponse(
            {{NetworkMessageType::HUMAN_READABLE_ERROR, error_message}});
          SendReadyForQuery(NetworkTransactionStateType::IDLE);
          return;
        }
      }
    }

    // send the attribute names
    PutTupleDescriptor(tuple_descriptor);

    // send the result rows
    SendDataRows(result, tuple_descriptor.size(), rows_affected);

    // The response to the SimpleQueryCommand is the query string.
    CompleteCommand(query, query_type, rows_affected);
  } else {
Beispiel #17
0
/*
 * Stage all files in the stream.
 */
static void
copyStream()
{
	int rval;
	FileInfo_t *file;
	int dcache;
	boolean_t reject;

	StageInit(Stream->vsn);

	/* Set loading flag for this stream. */
	PthreadMutexLock(&Stream->mutex);
	SET_FLAG(Stream->flags, SR_LOADING);
	PthreadMutexUnlock(&Stream->mutex);

	rval = LoadVolume();

	/* Reject if mount/open failed. */
	if (rval != 0) {
		PthreadMutexLock(&Stream->mutex);
		removeDcachedFile(Stream, rval);

		if (rval == ENODEV) {
			Stream->context = 0;
			PthreadMutexUnlock(&Stream->mutex);
			rejectRequest(0, B_TRUE);
			SET_FLAG(Instance->ci_flags, CI_shutdown);
		} else {
			PthreadMutexUnlock(&Stream->mutex);
			SendCustMsg(HERE, 19017, Stream->vsn);
			rejectRequest(rval, B_TRUE);
		}

		StageEnd();
		return;
	}

	/* VSN load has completed. */
	checkBuffers(Stream->vsn);

	PthreadMutexLock(&Stream->mutex);
	CLEAR_FLAG(Stream->flags, SR_LOADING);

	Instance->ci_seqnum = Stream->seqnum;
	reject = B_FALSE;

	/*
	 * Copy all files in stage stream request.  The files have
	 * been ordered to eliminate backward media positioning.
	 */

	while (STREAM_IS_VALID() && reject == B_FALSE) {

		/* Stop staging if parent died. */
		if (getppid() == 1) {
			SetErrno = 0;		/* set for trace */
			Trace(TR_ERR, "Detected stager daemon exit");

			Stream->first = EOS;
			SET_FLAG(Instance->ci_flags, CI_shutdown);
			break;
		}

		file = GetFile(Stream->first);

		PthreadMutexLock(&file->mutex);
		PthreadMutexUnlock(&Stream->mutex);

		/*
		 * If the first vsn, clear bytes read count.
		 * And if multivolume and stage -n set, initialize
		 * residual length.
		 */
		if (file->vsn_cnt == 0) {
			file->read = 0;
			if (GET_FLAG(file->flags, FI_MULTIVOL) &&
			    GET_FLAG(file->flags, FI_STAGE_NEVER)) {
				file->residlen = file->len;
			} else {
				file->residlen = 0;
			}
		}

		SET_FLAG(file->flags, FI_ACTIVE);

		PthreadMutexUnlock(&file->mutex);

		/* Set file in io control structure for archive read thread. */
		setIoThread(file);

		/* Log stage start. */
		file->eq = IoThread->io_drive;
		LogIt(LOG_STAGE_START, file);

		/*
		 * Check if last request was canceled.  If the last request
		 * was canceled, invalidate i/o buffers and clear cancel
		 * flag in the control structure.
		 */
		if (GET_FLAG(IoThread->io_flags, IO_cancel)) {
			ResetBuffers();
			CLEAR_FLAG(IoThread->io_flags, IO_cancel);
		}

		/*
		 * Next archive file.  If disk archive, we may be opening
		 * a disk archive tarball.
		 */
		if ((rval = NextArchiveFile()) == 0) {
			/* Prepare filesystem to receive staged file. */
			dcache = DiskCacheOpen(file);

		} else {
			/* Unable to open disk archive.  Error request. */
			Trace(TR_ERR, "Unable to open disk archive "
			    "copy: %d inode: %d.%d errno: %d",
			    file->copy + 1, file->id.ino, file->id.gen, errno);
			dcache = -1;
			file->error = errno;
			SendErrorResponse(file);
		}

		if (dcache >= 0 && rval == 0) {
			/*
			 * Notify reader thread that next file in stream
			 * is ready to be staged.
			 */
			ThreadStatePost(&IoThread->io_readReady);

			/* Write data to disk cache. */
			rval = DiskCacheWrite(file, dcache);

			if (rval != 0) {
				SendErrorResponse(file);

				/* Check if number of stream errors exceeded. */
				reject = ifMaxStreamErrors(file);
			}

			ThreadStateWait(&IoThread->io_readDone);

		} else if (rval != 0 && dcache >= 0) {
			/* Setup for error handling. */
			SetFileError(file, dcache, 0, EIO);
			SendErrorResponse(file);
		}

		EndArchiveFile();

		/* Remove file from stream before marking it as done. */
		PthreadMutexLock(&Stream->mutex);
		Stream->first = file->next;

		/* Device not available. */
		if (file->error == ENODEV) {
			SetErrno = 0;	/* set for trace */
			Trace(TR_ERR, "No device available");

			reject = B_TRUE;
			if (NumOpenFiles <= 0 && Instance->ci_first == NULL) {
				SET_FLAG(Instance->ci_flags, CI_shutdown);
				Instance->ci_busy = B_TRUE;
			}
		}

		/* Mark file staging as done. */
		SetStageDone(file);
		Stream->count--;

		if (Stream->first == EOS) {
			Stream->last = EOS;
		}

	}

	/* Reject rest of stages in this stream. */
	if (reject == B_TRUE) {
		if (Stream->first > EOS) {
			removeDcachedFile(Stream, ENODEV);
		}
		PthreadMutexUnlock(&Stream->mutex);
		rejectRequest(ENODEV, B_FALSE);
		PthreadMutexLock(&Stream->mutex);
	}

	/* Remove copy request, no one is waiting on it. */
	RemoveMapFile(copyRequestPath, Request, sizeof (CopyRequestInfo_t));
	Request = NULL;

	/* Ready to unload.  Mark stream as done. */
	SET_FLAG(Stream->flags, SR_DONE);
	PthreadMutexUnlock(&Stream->mutex);

	UnloadVolume();

	/*
	 * Unmap pages of memory.  Stream's memory
	 * mapped file is removed in parent.
	 */
	UnMapFile(Stream, sizeof (StreamInfo_t));
	Stream = NULL;

	StageEnd();
}