1*35d8d4d1SNiels Sascha Reedijk /* 2*35d8d4d1SNiels Sascha Reedijk * Copyright 2013 Haiku, Inc. All rights reserved. 3*35d8d4d1SNiels Sascha Reedijk * Distributed under the terms of the MIT License. 4*35d8d4d1SNiels Sascha Reedijk * 5*35d8d4d1SNiels Sascha Reedijk * Authors: 6*35d8d4d1SNiels Sascha Reedijk * Adrien Destugues, pulkomandy@pulkomandy.tk 7*35d8d4d1SNiels Sascha Reedijk */ 8*35d8d4d1SNiels Sascha Reedijk 9*35d8d4d1SNiels Sascha Reedijk 10*35d8d4d1SNiels Sascha Reedijk #include "DataRequest.h" 11*35d8d4d1SNiels Sascha Reedijk 12*35d8d4d1SNiels Sascha Reedijk #include <AutoDeleter.h> 13*35d8d4d1SNiels Sascha Reedijk #include <HttpAuthentication.h> 14*35d8d4d1SNiels Sascha Reedijk #include <mail_encoding.h> 15*35d8d4d1SNiels Sascha Reedijk #include <stdio.h> 16*35d8d4d1SNiels Sascha Reedijk 17*35d8d4d1SNiels Sascha Reedijk 18*35d8d4d1SNiels Sascha Reedijk BDataRequest::BDataRequest(const BUrl& url, BUrlProtocolListener* listener, 19*35d8d4d1SNiels Sascha Reedijk BUrlContext* context) 20*35d8d4d1SNiels Sascha Reedijk : BUrlRequest(url, listener, context, "data URL parser", "data"), 21*35d8d4d1SNiels Sascha Reedijk fResult() 22*35d8d4d1SNiels Sascha Reedijk { 23*35d8d4d1SNiels Sascha Reedijk fResult.SetContentType("text/plain"); 24*35d8d4d1SNiels Sascha Reedijk } 25*35d8d4d1SNiels Sascha Reedijk 26*35d8d4d1SNiels Sascha Reedijk 27*35d8d4d1SNiels Sascha Reedijk const BUrlResult& 28*35d8d4d1SNiels Sascha Reedijk BDataRequest::Result() const 29*35d8d4d1SNiels Sascha Reedijk { 30*35d8d4d1SNiels Sascha Reedijk return fResult; 31*35d8d4d1SNiels Sascha Reedijk } 32*35d8d4d1SNiels Sascha Reedijk 33*35d8d4d1SNiels Sascha Reedijk 34*35d8d4d1SNiels Sascha Reedijk status_t 35*35d8d4d1SNiels Sascha Reedijk BDataRequest::_ProtocolLoop() 36*35d8d4d1SNiels Sascha Reedijk { 37*35d8d4d1SNiels Sascha Reedijk BString mimeType; 38*35d8d4d1SNiels Sascha Reedijk BString charset; 39*35d8d4d1SNiels Sascha Reedijk const char* payload; 40*35d8d4d1SNiels Sascha Reedijk ssize_t length; 41*35d8d4d1SNiels Sascha Reedijk bool isBase64 = false; 42*35d8d4d1SNiels Sascha Reedijk 43*35d8d4d1SNiels Sascha Reedijk // The RFC has examples where some characters are URL-Encoded. 44*35d8d4d1SNiels Sascha Reedijk fUrl.UrlDecode(true); 45*35d8d4d1SNiels Sascha Reedijk 46*35d8d4d1SNiels Sascha Reedijk // The RFC says this uses a nonstandard scheme, so the path, query and 47*35d8d4d1SNiels Sascha Reedijk // fragment are a bit nonsensical. It would be nice to handle them, but 48*35d8d4d1SNiels Sascha Reedijk // some software (eg. WebKit) relies on data URIs with embedded "#" char 49*35d8d4d1SNiels Sascha Reedijk // in the data... 50*35d8d4d1SNiels Sascha Reedijk BString data = fUrl.UrlString(); 51*35d8d4d1SNiels Sascha Reedijk data.Remove(0, 5); // remove "data:" 52*35d8d4d1SNiels Sascha Reedijk 53*35d8d4d1SNiels Sascha Reedijk int separatorPosition = data.FindFirst(','); 54*35d8d4d1SNiels Sascha Reedijk 55*35d8d4d1SNiels Sascha Reedijk if (fListener != NULL) 56*35d8d4d1SNiels Sascha Reedijk fListener->ConnectionOpened(this); 57*35d8d4d1SNiels Sascha Reedijk 58*35d8d4d1SNiels Sascha Reedijk if (separatorPosition >= 0) { 59*35d8d4d1SNiels Sascha Reedijk BString meta = data; 60*35d8d4d1SNiels Sascha Reedijk meta.Truncate(separatorPosition); 61*35d8d4d1SNiels Sascha Reedijk data.Remove(0, separatorPosition + 1); 62*35d8d4d1SNiels Sascha Reedijk 63*35d8d4d1SNiels Sascha Reedijk int pos = 0; 64*35d8d4d1SNiels Sascha Reedijk while (meta.Length() > 0) { 65*35d8d4d1SNiels Sascha Reedijk // Extract next parameter 66*35d8d4d1SNiels Sascha Reedijk pos = meta.FindFirst(';', pos); 67*35d8d4d1SNiels Sascha Reedijk 68*35d8d4d1SNiels Sascha Reedijk BString parameter = meta; 69*35d8d4d1SNiels Sascha Reedijk if (pos >= 0) { 70*35d8d4d1SNiels Sascha Reedijk parameter.Truncate(pos); 71*35d8d4d1SNiels Sascha Reedijk meta.Remove(0, pos+1); 72*35d8d4d1SNiels Sascha Reedijk } else 73*35d8d4d1SNiels Sascha Reedijk meta.Truncate(0); 74*35d8d4d1SNiels Sascha Reedijk 75*35d8d4d1SNiels Sascha Reedijk // Interpret the parameter 76*35d8d4d1SNiels Sascha Reedijk if (parameter == "base64") { 77*35d8d4d1SNiels Sascha Reedijk isBase64 = true; 78*35d8d4d1SNiels Sascha Reedijk } else if (parameter.FindFirst("charset=") == 0) { 79*35d8d4d1SNiels Sascha Reedijk charset = parameter; 80*35d8d4d1SNiels Sascha Reedijk } else { 81*35d8d4d1SNiels Sascha Reedijk // Must be the MIME type 82*35d8d4d1SNiels Sascha Reedijk mimeType = parameter; 83*35d8d4d1SNiels Sascha Reedijk } 84*35d8d4d1SNiels Sascha Reedijk } 85*35d8d4d1SNiels Sascha Reedijk 86*35d8d4d1SNiels Sascha Reedijk if (charset.Length() > 0) 87*35d8d4d1SNiels Sascha Reedijk mimeType << ";" << charset; 88*35d8d4d1SNiels Sascha Reedijk fResult.SetContentType(mimeType); 89*35d8d4d1SNiels Sascha Reedijk 90*35d8d4d1SNiels Sascha Reedijk } 91*35d8d4d1SNiels Sascha Reedijk 92*35d8d4d1SNiels Sascha Reedijk ArrayDeleter<char> buffer; 93*35d8d4d1SNiels Sascha Reedijk if (isBase64) { 94*35d8d4d1SNiels Sascha Reedijk // Check that the base64 data is properly padded (we process characters 95*35d8d4d1SNiels Sascha Reedijk // by groups of 4 and there must not be stray chars at the end as 96*35d8d4d1SNiels Sascha Reedijk // Base64 specifies padding. 97*35d8d4d1SNiels Sascha Reedijk if (data.Length() & 3) 98*35d8d4d1SNiels Sascha Reedijk return B_BAD_DATA; 99*35d8d4d1SNiels Sascha Reedijk 100*35d8d4d1SNiels Sascha Reedijk buffer.SetTo(new char[data.Length() * 3 / 4]); 101*35d8d4d1SNiels Sascha Reedijk payload = buffer.Get(); 102*35d8d4d1SNiels Sascha Reedijk // payload must be a const char* so we can assign data.String() to 103*35d8d4d1SNiels Sascha Reedijk // it below, but decode_64 modifies buffer. 104*35d8d4d1SNiels Sascha Reedijk length = decode_base64(buffer.Get(), data.String(), data.Length()); 105*35d8d4d1SNiels Sascha Reedijk 106*35d8d4d1SNiels Sascha Reedijk // There may be some padding at the end of the base64 stream. This 107*35d8d4d1SNiels Sascha Reedijk // prevents us from computing the exact length we should get, so allow 108*35d8d4d1SNiels Sascha Reedijk // for some error margin. 109*35d8d4d1SNiels Sascha Reedijk if (length > data.Length() * 3 / 4 110*35d8d4d1SNiels Sascha Reedijk || length < data.Length() * 3 / 4 - 3) { 111*35d8d4d1SNiels Sascha Reedijk return B_BAD_DATA; 112*35d8d4d1SNiels Sascha Reedijk } 113*35d8d4d1SNiels Sascha Reedijk } else { 114*35d8d4d1SNiels Sascha Reedijk payload = data.String(); 115*35d8d4d1SNiels Sascha Reedijk length = data.Length(); 116*35d8d4d1SNiels Sascha Reedijk } 117*35d8d4d1SNiels Sascha Reedijk 118*35d8d4d1SNiels Sascha Reedijk fResult.SetLength(length); 119*35d8d4d1SNiels Sascha Reedijk 120*35d8d4d1SNiels Sascha Reedijk if (fListener != NULL) { 121*35d8d4d1SNiels Sascha Reedijk fListener->HeadersReceived(this, fResult); 122*35d8d4d1SNiels Sascha Reedijk if (length > 0) { 123*35d8d4d1SNiels Sascha Reedijk fListener->DataReceived(this, payload, 0, length); 124*35d8d4d1SNiels Sascha Reedijk fListener->DownloadProgress(this, length, length); 125*35d8d4d1SNiels Sascha Reedijk } 126*35d8d4d1SNiels Sascha Reedijk } 127*35d8d4d1SNiels Sascha Reedijk 128*35d8d4d1SNiels Sascha Reedijk return B_OK; 129*35d8d4d1SNiels Sascha Reedijk } 130