1
0
Fork 0
arangodb/arangod/GeneralServer/VstCommTask.h

144 lines
5.1 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Christoph Uhde
////////////////////////////////////////////////////////////////////////////////
#ifndef ARANGOD_GENERAL_SERVER_VST_COMM_TASK_H
#define ARANGOD_GENERAL_SERVER_VST_COMM_TASK_H 1
#include "Basics/Common.h"
#include "GeneralServer/GeneralCommTask.h"
#include "lib/Rest/VstMessage.h"
#include "lib/Rest/VstRequest.h"
#include "lib/Rest/VstResponse.h"
#include <stdexcept>
namespace arangodb {
namespace rest {
class VstCommTask final : public GeneralCommTask {
public:
VstCommTask(GeneralServer& server, std::unique_ptr<Socket> socket,
ConnectionInfo&&, double timeout,
ProtocolVersion protocolVersion, bool skipSocketInit = false);
arangodb::Endpoint::TransportType transportType() override {
return arangodb::Endpoint::TransportType::VST;
}
// whether or not this task can mix sync and async I/O
bool canUseMixedIO() const override;
protected:
// read data check if chunk and message are complete
// if message is complete execute a request
bool processRead(double startTime) override;
std::unique_ptr<GeneralResponse> createResponse(rest::ResponseCode,
uint64_t messageId) override final;
// @brief send simple response including response body
void addSimpleResponse(rest::ResponseCode, rest::ContentType, uint64_t messageId,
velocypack::Buffer<uint8_t>&&) override;
// convert from GeneralResponse to VstResponse ad dispatch request to class
// internal addResponse
void addResponse(GeneralResponse&, RequestStatistics*) override;
bool allowDirectHandling() const override final { return false; }
private:
// process the VST 1000 request type
void handleAuthHeader(VPackSlice const& header, uint64_t messageId);
// reets the internal state this method can be called to clean up when the
// request handling aborts prematurely
void closeTask(rest::ResponseCode code = rest::ResponseCode::SERVER_ERROR);
private:
using MessageID = uint64_t;
struct IncompleteVPackMessage {
IncompleteVPackMessage(uint32_t length, std::size_t numberOfChunks)
: _length(length),
_buffer(_length),
_numberOfChunks(numberOfChunks),
_currentChunk(0) {}
uint32_t _length; // length of total message in bytes
VPackBuffer<uint8_t> _buffer;
std::size_t _numberOfChunks;
std::size_t _currentChunk;
};
std::unordered_map<MessageID, IncompleteVPackMessage> _incompleteMessages;
static size_t const _bufferLength = 4096UL;
static size_t const _chunkMaxBytes = 1000UL;
struct ProcessReadVariables {
ProcessReadVariables()
: _currentChunkLength(0),
_readBufferOffset(0),
_cleanupLength(_bufferLength - _chunkMaxBytes - 1) {}
uint32_t _currentChunkLength; // size of chunk processed or 0 when
// expecting new chunk
size_t _readBufferOffset; // data up to this position has been processed
std::size_t _cleanupLength; // length of data after that the read buffer
// will be cleaned
};
ProcessReadVariables _processReadVariables;
struct ChunkHeader {
std::size_t _headerLength;
uint32_t _chunkLength;
uint32_t _chunk;
uint64_t _messageID;
uint64_t _messageLength;
bool _isFirst;
};
bool isChunkComplete(char*); // sub-function of processRead
ChunkHeader readChunkHeader(); // sub-function of processRead
void replyToIncompleteMessages();
// Returns true if and only if there was no error, if false is returned,
// the connection is closed
bool getMessageFromSingleChunk(ChunkHeader const& chunkHeader,
VstInputMessage& message, bool& doExecute,
char const* vpackBegin, char const* chunkEnd);
// Returns true if and only if there was no error, if false is returned,
// the connection is closed
bool getMessageFromMultiChunks(ChunkHeader const& chunkHeader,
VstInputMessage& message, bool& doExecute,
char const* vpackBegin, char const* chunkEnd);
private:
/// Is the current user authorized
bool _authorized;
rest::AuthenticationMethod _authMethod;
ProtocolVersion _protocolVersion;
uint32_t _maxChunkSize;
};
} // namespace rest
} // namespace arangodb
#endif