Reintroduce BUrlResult and add BDataRequest

* BUrlResult is back, with ContentType and Length methods.
* BHttpResult subclasses it and use HTTP header fields to implement
those
* Introduce BDataRequest for "data" URIs. These embed the data inside
the URI, either as plaintext or base64 encoded.
This commit is contained in:
Adrien Destugues 2013-12-09 20:26:13 +01:00
parent d43ede6002
commit 824dd0a834
12 changed files with 257 additions and 12 deletions

View File

@ -0,0 +1,29 @@
/*
* Copyright 2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Adrien Destugues, pulkomandy@pulkomandy.tk
*/
#ifndef _B_DATA_REQUEST_H_
#define _B_DATA_REQUEST_H_
#include <UrlRequest.h>
class BDataRequest: public BUrlRequest {
public:
BDataRequest(const BUrl& url,
BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL);
const BUrlResult& Result() const;
private:
status_t _ProtocolLoop();
private:
BUrlResult fResult;
};
#endif

View File

@ -19,10 +19,13 @@ public:
BUrlContext* context = NULL);
virtual ~BFileRequest();
const BUrlResult& Result() const;
void SetDisableListener(bool disable);
private:
status_t _ProtocolLoop();
private:
BUrlResult fResult;
};

View File

@ -47,7 +47,7 @@ public:
const ssize_t size = -1);
void AdoptHeaders(BHttpHeaders* const headers);
const BHttpResult& Result() const;
const BUrlResult& Result() const;
const char* StatusString(status_t threadStatus) const;
static bool IsInformationalStatusCode(int16 code);

View File

@ -2,22 +2,22 @@
* Copyright 2010 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _B_URL_RESULT_H_
#define _B_URL_RESULT_H_
#ifndef _B_HTTP_RESULT_H_
#define _B_HTTP_RESULT_H_
#include <iostream>
#include <DataIO.h>
#include <HttpHeaders.h>
#include <String.h>
#include <Url.h>
#include <UrlResult.h>
class BUrlRequest;
class BHttpResult {
class BHttpResult: public BUrlResult {
friend class BHttpRequest;
public:
@ -30,6 +30,8 @@ public:
// Result parameters access
const BUrl& Url() const;
BString ContentType() const;
size_t Length() const;
// HTTP-Specific stuff
const BHttpHeaders& Headers() const;
@ -45,7 +47,6 @@ public:
private:
BUrl fUrl;
// TODO: HTTP specific stuff should not live here.
BHttpHeaders fHeaders;
int32 fStatusCode;
BString fStatusString;

View File

@ -9,6 +9,7 @@
#include <Url.h>
#include <UrlContext.h>
#include <UrlProtocolListener.h>
#include <UrlResult.h>
#include <OS.h>
@ -43,6 +44,7 @@ public:
status_t Status() const;
virtual const char* StatusString(status_t threadStatus)
const;
virtual const BUrlResult& Result() const = 0;
protected:

View File

@ -0,0 +1,27 @@
/*
* Copyright 2010 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _B_URL_RESULT_H_
#define _B_URL_RESULT_H_
#include <String.h>
class BUrlResult {
public:
virtual ~BUrlResult();
void SetContentType(BString contentType);
void SetLength(size_t length);
virtual BString ContentType() const;
virtual size_t Length() const;
private:
BString fContentType;
BString fCharset;
size_t fLength;
};
#endif

View File

@ -0,0 +1,106 @@
/*
* 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 <HttpAuthentication.h>
#include <mail_encoding.h>
#include <stdio.h>
BDataRequest::BDataRequest(const BUrl& url, BUrlProtocolListener* listener,
BUrlContext* context)
: BUrlRequest(url, 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;
size_t length;
bool isBase64 = false;
fUrl.UrlDecode(true);
BString data = fUrl.Path();
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)
{
// Extract next parameter
pos = meta.FindFirst(';', pos);
BString parameter = meta;
if(pos >= 0) {
parameter.Truncate(pos);
meta.Remove(0, pos+1);
} else
meta.Truncate(0);
// Interpret the parameter
if(parameter == "base64") {
isBase64 = true;
} else if(parameter.FindFirst("charset=") == 0) {
charset = parameter;
} else {
// Must be the MIME type
mimeType = parameter;
}
}
if (charset.Length() > 0)
mimeType << ";" << charset;
fResult.SetContentType(mimeType);
}
if (isBase64) {
char* buffer = new char[data.Length() * 4 / 3];
payload = buffer;
// payload must be a const char* so we can assign data.String() to
// it below, but decode_64 modifies buffer.
length = decode_base64(buffer, data.String(), data.Length());
} else {
payload = data.String();
length = data.Length();
}
fResult.SetLength(length);
if (fListener != NULL) {
fListener->DownloadProgress(this, length, length);
if (length > 0)
fListener->DataReceived(this, payload, length);
}
if (isBase64)
delete payload;
return B_PROT_SUCCESS;
}

View File

@ -7,19 +7,18 @@
*/
#include <new>
#include <stdlib.h>
#include <arpa/inet.h>
#include <File.h>
#include <FileRequest.h>
#include <NodeInfo.h>
BFileRequest::BFileRequest(const BUrl& url, BUrlProtocolListener* listener,
BUrlContext* context)
:
BUrlRequest(url, listener, context, "BUrlProtocol.File", "file")
BUrlRequest(url, listener, context, "BUrlProtocol.File", "file"),
fResult()
{
}
@ -29,6 +28,13 @@ BFileRequest::~BFileRequest()
}
const BUrlResult&
BFileRequest::Result() const
{
return fResult;
}
status_t
BFileRequest::_ProtocolLoop()
{
@ -44,6 +50,7 @@ BFileRequest::_ProtocolLoop()
off_t size = 0;
file.GetSize(&size);
fListener->DownloadProgress(this, size, size);
fResult.SetLength(size);
ssize_t chunkSize;
char chunk[4096];
@ -51,5 +58,10 @@ BFileRequest::_ProtocolLoop()
fListener->DataReceived(this, chunk, chunkSize);
}
BNodeInfo info(&file);
char mimeType[B_MIME_TYPE_LENGTH + 1];
if (info.GetType(mimeType) == B_OK)
fResult.SetContentType(mimeType);
return B_PROT_SUCCESS;
}

View File

@ -58,6 +58,23 @@ BHttpResult::Url() const
}
BString
BHttpResult::ContentType() const
{
return Headers()["Content-Type"];
}
size_t
BHttpResult::Length() const
{
const char* length = Headers()["Content-Length"];
if (length == NULL)
return 0;
return atoi(length);
}
const BHttpHeaders&
BHttpResult::Headers() const
{

View File

@ -55,6 +55,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
# TODO: The HTTP stuff should all go into an add-on. It needs
# linking against libcrypto.so and only the add-on should link
# against it.
DataRequest.cpp
HttpAuthentication.cpp
HttpHeaders.cpp
HttpForm.cpp
@ -74,6 +75,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
UrlProtocolListener.cpp
UrlProtocolRoster.cpp
UrlRequest.cpp
UrlResult.cpp
UrlSynchronousRequest.cpp
:

View File

@ -11,10 +11,11 @@
#include <new>
#include <UrlRequest.h>
#include <DataRequest.h>
#include <Debug.h>
#include <FileRequest.h>
#include <HttpRequest.h>
#include <Debug.h>
#include <UrlRequest.h>
static BUrlContext gDefaultContext;
@ -36,6 +37,8 @@ BUrlProtocolRoster::MakeRequest(const BUrl& url,
context);
} else if (url.Protocol() == "file") {
return new(std::nothrow) BFileRequest(url, listener, context);
} else if (url.Protocol() == "data") {
return new(std::nothrow) BDataRequest(url, listener, context);
}
return NULL;

View File

@ -0,0 +1,43 @@
/*
* Copyright 2013 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Adrien Destugues, pulkomandy@pulkomandy.tk
*/
#include <UrlResult.h>
BUrlResult::~BUrlResult()
{
}
void
BUrlResult::SetContentType(BString contentType)
{
fContentType = contentType;
}
void
BUrlResult::SetLength(size_t length)
{
fLength = length;
}
BString
BUrlResult::ContentType() const
{
return fContentType;
}
size_t
BUrlResult::Length() const
{
return fLength;
}