* Copyright 2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Adrien Destugues, pulkomandy@pulkomandy.tk
*/
#include "DataRequest.h"
#include <AutoDeleter.h>
#include <HttpAuthentication.h>
#include <mail_encoding.h>
#include <stdio.h>
using namespace BPrivate::Network;
BDataRequest::BDataRequest(const BUrl& url, BDataIO* output,
BUrlProtocolListener* listener,
BUrlContext* context)
:
BUrlRequest(url, output, listener, context, "data URL parser", "data"),
fResult()
{
fResult.SetContentType("text/plain");
}
const BUrlResult&
BDataRequest::Result() const
{
return fResult;
}
status_t
BDataRequest::_ProtocolLoop()
{
BString mimeType;
BString charset;
const char* payload;
ssize_t length;
bool isBase64 = false;
BString data = fUrl.UrlString();
data.Remove(0, 5);
int separatorPosition = data.FindFirst(',');
if (fListener != NULL)
fListener->ConnectionOpened(this);
if (separatorPosition >= 0) {
BString meta = data;
meta.Truncate(separatorPosition);
data.Remove(0, separatorPosition + 1);
int pos = 0;
while (meta.Length() > 0) {
pos = meta.FindFirst(';', pos);
BString parameter = meta;
if (pos >= 0) {
parameter.Truncate(pos);
meta.Remove(0, pos+1);
} else
meta.Truncate(0);
if (parameter == "base64") {
isBase64 = true;
} else if (parameter.FindFirst("charset=") == 0) {
charset = parameter;
} else {
mimeType = parameter;
}
}
if (charset.Length() > 0)
mimeType << ";" << charset;
fResult.SetContentType(mimeType);
}
ArrayDeleter<char> buffer;
if (isBase64) {
if (data.Length() & 3)
return B_BAD_DATA;
buffer.SetTo(new char[data.Length() * 3 / 4]);
payload = buffer.Get();
length = decode_base64(buffer.Get(), data.String(), data.Length());
if (length > data.Length() * 3 / 4
|| length < data.Length() * 3 / 4 - 3) {
return B_BAD_DATA;
}
} else {
payload = data.String();
length = data.Length();
}
fResult.SetLength(length);
if (fListener != NULL)
fListener->HeadersReceived(this);
if (length > 0) {
if (fOutput != NULL) {
size_t written = 0;
status_t err = fOutput->WriteExactly(payload, length, &written);
if (fListener != NULL && written > 0)
fListener->BytesWritten(this, written);
if (err != B_OK)
return err;
if (fListener != NULL)
fListener->DownloadProgress(this, written, written);
}
}
return B_OK;
}