I created a simple client and server using CPPRESTSDK
. The client sends an image and on the server, I save the incoming file and then start doing the processing phase afterwards.
Now I want to check if the sent file is actually an image file and not some other random file. For that, I check the first few bytes of the file and this allows me to know what I'm dealing with.
This is the snippet responsible for saving the file:
//...
auto fileStream = std::make_shared<Concurrency::streams::ostream >();
Concurrency::streams::ostream outFile = Concurrency::streams::fstream::open_ostream(tmpFileName).get();
*fileStream = outFile;
uintmax_t bytesRead = 0;
int ret = 1;
bool isChecked = false;
while (ret > 0)
{
ret = request.body().read(fileStream->streambuf(), this->READ_CHUNK).get();
bytesRead += ret;
if (!isChecked)
{
isChecked = true;
auto streamBuffer = fileStream->streambuf();
unsigned char byteBuffer[4];
for (int i = 0; i < 4; i++)
{
byteBuffer[i] = (unsigned int)streamBuffer.bumpc().get();
std::cout << byteBuffer[i] << ", ";
}
// reset the read pointer
//streamBuffer.seekpos(std::streampos(), std::ios::in);
// check and see if this is indeed an image file
std::string imgFormat = Utils::Misc::GetImageType(byteBuffer);
if (imgFormat == "")
{
fileStream->close().get();
auto msg = U("Unsupported file has been sent! Expected an image file such as a JPEG, PNG, OR BMP");
this->ReplyMessage(request, status_codes::BadRequest, json::value::string(msg));
return;
}
}
ucout << "--" << bytesRead << U(" bytes read so far[")
<< Utils::Misc::GetFileSize(bytesRead , Utils::Misc::FileSizeTypes::KByte)
<< U(" KB]") << std::endl;
if (bytesRead > MAX_FILE_SIZE)
break;
}
// Close the file.
fileStream->close().get();
// ...
This clearly fails as the fileStream
is an ostream
and its can_read
returns false
thus bumpc()
doesn't work. So how should I be going about this? How can I access the underlying byte buffer and see what was received so far?
Using the request
's streambuf()
also doesn't yield any success as the file pointer seems not to be moveable, thus doing something like seekpos(std::streampos(0), std::ios::in)
will not reset it to the beginning of the buffer. What am I missing here?
You need to open the file stream for both reading and writing, by explicitly passing the mode
parameter to the open_ostream
function. If you don't specify this parameter, it defaults to std::ios_base::out
.
Concurrency::streams::fstream::open_ostream(tmpFileName, std::ios_base::in | std::ios_base::out).get();
Then the filestream should be created as readable, and you should be able to write the first chunk, seek back to the start of the file, read four bytes, then seek forwards to the end of the first chunk.
An alternative, possibly cleaner approach would be to read the first chunk to a stringstream
, parse the image format from the first four bytes of that, and then (if the image format is valid and the file is to be saved) create the filestream, write the contents of the stringstream to the filestream, and then continue writing the remainder of the file chunks straight to the filestream.