Upload file via multipart request - http

I need to upload a zip file to a url that accepts files passed in a multipart request. The name of the part in the "multipart/form-data" request to bind to is "archive".
What I have so far:
auto f = new BufferedFile(<path_to_file>, FileMode.In);
scope (exit) f.close();
http = HTTP(<post_url>);
http.addRequestHeader("Content-Type", "multipart/form-data;boundary=heregoes");
http.verifyPeer(false);
http.method = HTTP.Method.post;
http.onSend = (void[] data){
return f.read(cast(ubyte[]) data);
};
http.contentLength = cast(size_t) f.size;
http.setCookieJar("<cookie_file_used_for_auth>");
http.perform();
How can I set the key "archive" in the request to map the file to?
Thanks

I don't use std.net.curl much so I don't know if there's an easier way, but the data you're sending is just a blob on the wire, so you could set the other values manually.
Don't just send the data, put it in a MIME envelope. I wrote this little class a while ago to help form that:
/// Creates a multipart/form-data object that is suitable for file uploads and other kinds of POST
class FormData {
struct MimePart {
string name;
const(void)[] data;
string contentType;
string filename;
}
MimePart[] parts;
void append(string key, in void[] value, string contentType = null, string filename = null) {
parts ~= MimePart(key, value, contentType, filename);
}
private string boundary = "0016e64be86203dd36047610926a"; // FIXME
ubyte[] toBytes() {
string data;
foreach(part; parts) {
data ~= "--" ~ boundary ~ "\r\n";
data ~= "Content-Disposition: form-data; name=\""~part.name~"\"";
if(part.filename !is null)
data ~= "; filename=\""~part.filename~"\"";
data ~= "\r\n";
if(part.contentType !is null)
data ~= "Content-Type: " ~ part.contentType ~ "\r\n";
data ~= "\r\n";
data ~= cast(string) part.data;
data ~= "\r\n";
}
data ~= "--" ~ boundary ~ "--\r\n";
return cast(ubyte[]) data;
}
}
I know that code sucks and I haven't tested it recently but the output eyeballs to be right. It should work like this:
auto data = new FormData();
data.append("archive", "YOUR DATA", "application/octet-stream"); // or whatever mime type you need
auto bytes = data.toBytes();
Then you send bytes instead of your file contents when curl asks for it. The setPostData method of HTTP looks like a place to put it. Remember to set your content type in the set post data too to the multipart/form-data with the boundary (you can change the one in my class if you like).
http://dlang.org/phobos/std_net_curl.html#setPostData
I know the curl library has functions to do this for you too... but I don't think the high level std.net.curl interface exposes them :(

Related

How to set a field with multi-value into a Post request?

This command works fine on Linux terminal:
curl -X POST "https://my-api.plantnet.org/v2/identify/all?api-key=11111111111111111111" -H "accept: application/json" -F "organs=flower" -F "organs=leaf" -F "images=#images/image_1.jpeg" -F "images=#images/image_2.jpeg"
As you may have seen there are two multi-value fields,organs and images, one is for String objects and the another is for File objects.
I've made this code:
static Future<T> postFilesAndGetJson<T>(String url, {List<MapEntry<String, String>> paths, List<MapEntry<String, String>> fields}) async {
var request = http.MultipartRequest('POST', Uri.parse(url));
if (paths != null && paths.isNotEmpty) {
paths.forEach((path) {
var file = File.fromUri(Uri.parse(path.value));
var multipartFile = http.MultipartFile.fromBytes(
path.key, file.readAsBytesSync(), filename: p.basename(file.path)
);
request.files.add(multipartFile);
});
}
if (fields != null && fields.isNotEmpty) {
request.fields.addEntries(fields);
}
return http.Response
.fromStream(await request.send())
.then((response) {
if (response.statusCode == 200) {
return jsonDecode(response.body) as T;
}
print('Status Code : ${response.statusCode}...');
return null;
});
}
And it works fine while field names are different, so for this case it doesn't work because I get status code 400 (Bad Request).
request.fields property is Map<String, String> so I cannot (apparently) set a List<String> as value. Similar case is for request.files.
How to work with multi-value fields?
The files are actually OK having duplicate field names. The 400 error you get is probably because you send two images but only one organs. So looks like the only thing you need to fix is sending multiple fields of the same name.
Having no better ideas, you may copy the original MultipartRequest and create your own class like MultipartListRequest. Then change fields from a map to a list (changed lines are commented):
import 'dart:convert';
import 'dart:math';
import 'package:http/http.dart'; // CHANGED
import 'package:http/src/utils.dart'; // CHANGED
import 'package:http/src/boundary_characters.dart'; // CHANGED
final _newlineRegExp = RegExp(r'\r\n|\r|\n');
class MultipartListRequest extends BaseRequest { // CHANGED
/// The total length of the multipart boundaries used when building the
/// request body.
///
/// According to http://tools.ietf.org/html/rfc1341.html, this can't be longer
/// than 70.
static const int _boundaryLength = 70;
static final Random _random = Random();
/// The form fields to send for this request.
final fields = <MapEntry<String, String>>[]; // CHANGED
/// The list of files to upload for this request.
final files = <MultipartFile>[];
MultipartListRequest(String method, Uri url) : super(method, url);
/// The total length of the request body, in bytes.
///
/// This is calculated from [fields] and [files] and cannot be set manually.
#override
int get contentLength {
var length = 0;
fields.forEach((field) { // CHANGED
final name = field.key; // CHANGED
final value = field.value; // CHANGED
length += '--'.length +
_boundaryLength +
'\r\n'.length +
utf8.encode(_headerForField(name, value)).length +
utf8.encode(value).length +
'\r\n'.length;
});
for (var file in files) {
length += '--'.length +
_boundaryLength +
'\r\n'.length +
utf8.encode(_headerForFile(file)).length +
file.length +
'\r\n'.length;
}
return length + '--'.length + _boundaryLength + '--\r\n'.length;
}
#override
set contentLength(int? value) {
throw UnsupportedError('Cannot set the contentLength property of '
'multipart requests.');
}
/// Freezes all mutable fields and returns a single-subscription [ByteStream]
/// that will emit the request body.
#override
ByteStream finalize() {
// TODO: freeze fields and files
final boundary = _boundaryString();
headers['content-type'] = 'multipart/form-data; boundary=$boundary';
super.finalize();
return ByteStream(_finalize(boundary));
}
Stream<List<int>> _finalize(String boundary) async* {
const line = [13, 10]; // \r\n
final separator = utf8.encode('--$boundary\r\n');
final close = utf8.encode('--$boundary--\r\n');
for (var field in fields) { // CHANGED
yield separator;
yield utf8.encode(_headerForField(field.key, field.value));
yield utf8.encode(field.value);
yield line;
}
for (final file in files) {
yield separator;
yield utf8.encode(_headerForFile(file));
yield* file.finalize();
yield line;
}
yield close;
}
/// Returns the header string for a field.
///
/// The return value is guaranteed to contain only ASCII characters.
String _headerForField(String name, String value) {
var header =
'content-disposition: form-data; name="${_browserEncode(name)}"';
if (!isPlainAscii(value)) {
header = '$header\r\n'
'content-type: text/plain; charset=utf-8\r\n'
'content-transfer-encoding: binary';
}
return '$header\r\n\r\n';
}
/// Returns the header string for a file.
///
/// The return value is guaranteed to contain only ASCII characters.
String _headerForFile(MultipartFile file) {
var header = 'content-type: ${file.contentType}\r\n'
'content-disposition: form-data; name="${_browserEncode(file.field)}"';
if (file.filename != null) {
header = '$header; filename="${_browserEncode(file.filename!)}"';
}
return '$header\r\n\r\n';
}
/// Encode [value] in the same way browsers do.
String _browserEncode(String value) =>
// http://tools.ietf.org/html/rfc2388 mandates some complex encodings for
// field names and file names, but in practice user agents seem not to
// follow this at all. Instead, they URL-encode `\r`, `\n`, and `\r\n` as
// `\r\n`; URL-encode `"`; and do nothing else (even for `%` or non-ASCII
// characters). We follow their behavior.
value.replaceAll(_newlineRegExp, '%0D%0A').replaceAll('"', '%22');
/// Returns a randomly-generated multipart boundary string
String _boundaryString() {
var prefix = 'dart-http-boundary-';
var list = List<int>.generate(
_boundaryLength - prefix.length,
(index) =>
boundaryCharacters[_random.nextInt(boundaryCharacters.length)],
growable: false);
return '$prefix${String.fromCharCodes(list)}';
}
}
(Would be better to subclass, but many valuable things are private there.)
Then in your code set the fields using addAll instead of addEntries:
request.fields.addAll(fields);
I see that you have already submitted an issue to Dart http package. This is good.

how can we store a html page into sqlite in blackberry on memory card / phone memory?

Below code specifies that we we can make http connection in blackberry and how to store html page as a string?
I am doing this but I am able to get that http request but when I get response i.e http_ok it is not correct so that I can save text oh html as a string and I can further store that into sqlite.
LabelField title = new LabelField("SQLite Create Database Sample",
LabelField.ELLIPSIS |
LabelField.USE_ALL_WIDTH);
setTitle(title);
add(new RichTextField("Creating a database."));
argURL="https://www.google.com:80";
try {
connDesc = connFact.getConnection(argURL);
if (connDesc != null) {
httpConn = (HttpConnection) connDesc.getConnection();
// //Send Data on this connection
// httpConn.setRequestMethod(HttpConnection.GET);
// //Server Response
StringBuffer strBuffer = new StringBuffer();
inStream = httpConn.openInputStream();
int chr;
int retResponseCode = httpConn.getResponseCode();
if (retResponseCode == HttpConnection.HTTP_OK) {
if (inStream != null) {
while ((chr = inStream.read()) != -1) {
strBuffer.append((char) chr);
}
serverResponceStr = strBuffer.toString();
// appLe.alertForms.get_userWaitAlertForm().append("\n"+serverResponceStr);
//returnCode = gprsConstants.retCodeSuccess;
}
} else {
//returnCode = gprsConstants.retCodeNOK;
}
}
} catch (Exception excp) {
//returnCode = gprsConstants.retCodeDisconn;
excp.printStackTrace();
} `enter code here`
The code does not perform any database functionality, however I tested and it does successfully perform an HttpRequest to an external URL. The data that comes back is based on the response of the server you are making the request to.
The code I used can be found here:
http://snipt.org/vrl7
The only modifications is to keep a running summary of various events, and the response is displayed in the RichTextField. Basically, this looks to be working as intended, and the resulting String should be able to be saved however you see fit; though you may need to be cautious of encoding when saving to a database so that special characters are not lost or misinterpreted.

In PlayN, how do I use the Storage interface to persist data?

I'm looking for a code example that demonstrates practical real-world usage of the Storage interface. I'm especially interested in HTML5 implementation. I've just started working on my own proof-of-concept, so I'll post that if no better answers arrive before then.
The Storage interface is introduced in this Google presentation here:
http://playn-2011.appspot.com/
Here's some code that demonstrates the use of the storage interface together with PlayN's JSON interface:
private void loadStoredData() {
// storage parameters
String storageKey = "jsonData";
Json.Object jsonData = PlayN.json().createObject();
// to reset storage, uncomment this line
//PlayN.storage().removeItem(storageKey);
// attempt to load stored data
String jsonString = PlayN.storage().getItem(storageKey);
// if not loaded, create stored data
if ( jsonString == null ) {
DemoApi.log("stored data not found");
jsonData.put("firstWrite", new Date().toString());
// else display data
} else {
jsonData = PlayN.json().parse(jsonString);
DemoApi.log("stored data loaded");
DemoApi.log("data first written at " + jsonData.getString("firstWrite"));
DemoApi.log("data last read at " + jsonData.getString("lastRead"));
DemoApi.log("data last written at " + jsonData.getString("lastWrite"));
}
// update last read
jsonData.put("lastRead", new Date().toString());
// write data (this works in Java -- not in HTML)
// see https://stackoverflow.com/q/10425877/1093087
/*
Json.Writer jsonWriter = PlayN.json().newWriter();
jsonWriter.object(jsonData).done();
jsonString = jsonWriter.write();
*/
// alternative write routine
Json.Writer jsonWriter = PlayN.json().newWriter();
jsonWriter.object();
for ( String key : jsonData.keys() ) {
jsonWriter.value(key, jsonData.getString(key));
}
jsonWriter.end();
jsonString = jsonWriter.write();
// store data as json
PlayN.storage().setItem(storageKey, jsonString);
// confirm
if ( PlayN.storage().isPersisted() ) {
DemoApi.log("data successfully persisted");
} else {
DemoApi.log("failed to persist data");
}
}
There's one little hitch with the Json.Writer that seems a bit buggy that I document in this question here: In the HTML version of PlayN, why does the following JSON-handling code throw an exception?

Render image in asp.net MVC

My scenario is this:
I create o custom report based on a stored procedure that returns three columns (person_id[long], name[varchar(100)], age[int], photo[image]). Those are the columns and types in my database table.
Right now i'm using something like this for each image of the report.
<img src="<%= Url.Action("ShowImage", "Reports", new {personId = result["PERSON_ID"]}) %>" />
with ShowImage being
public virtual ActionResult ShowImage(long? personId)
{
try
{
if (personId.HasValue)
{
byte[] imageArray = StudentClient.GetPersonPhotoById(personId.Value);
if (imageArray == null)
return File(noPhotoArray, "image/jpg");
#region Validate that the uploaded picture is an image - temporary code
// Get Mime Type
byte[] buffer = new byte[256];
buffer = imageArray.Take(imageArray.Length >= 256 ? 256 : imageArray.Length).ToArray();
var mimeType = UrlmonMimeType.GetMimeType(buffer);
if (String.IsNullOrEmpty(mimeType) || mimeType.IndexOf("image") == -1)
return File(noPhotoArray, "image/jpg");
#endregion
return File(imageArray, "image/jpg");
}
}
catch
{
return File(noPhotoArray, "image/jpg");
}
}
I would like to use some sort of alternative because this is very stresful due to the fact the ShowImage() calls a service method StudentClient.GetPersonPhotoById(personId.Value); for every single picture, meaning allot of calls to the service and the DB also.
I would like to actually use that photo column that returns a byte array instead of using the Person_id column through the ShowImage controller method.
That would practicaly reduce the number of calls to the service to 0 and use the actual data from the image column. This seems pretty straight forward but I struggle to find a solution.
Thank you!
Simplest solution - use OutputCache. Moreover, you can set cache location to client, and the browser will cache the images once they're downloaded. VaryByParam will give you the ability to cache images depending on personId.
There's quite a neat technique where you can stream the binary data directly from the SQL Server to the client, via the webserver.
This is my code for doing it:
public void StreamFile(Stream stream)
{
DbDataReader dr = LoadDbStream();
if (!dr.Read())
return;
const int BUFFERSIZE = 512;
byte[] Buffer = new byte[BUFFERSIZE];
long StartIndex = 0;
long Read = dr.GetBytes(0, StartIndex, Buffer, 0, BUFFERSIZE);
while (Read == BUFFERSIZE)
{
stream.Write(Buffer, 0, BUFFERSIZE);
StartIndex += BUFFERSIZE;
Read = dr.GetBytes(0, StartIndex, Buffer, 0, BUFFERSIZE);
}
stream.Write(Buffer, 0, (int)Read);
}
private DbDataReader LoadDbStream()
{
DbCommand cmd = Cms.Data.GetCommand("SELECT Data FROM CMS_Files WHERE FileId = #FileId", "#FileId", Id.ToString());
cmd.CommandType = System.Data.CommandType.Text;
cmd.Connection.Open();
return cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection);
}
The command object is an ordinary command object. The key part is the CommandBehavior.SequentialAccess flag as this makes sql server only send data when you ask for. You therefore can only read the columns in the order they are specified in the query. the other point to make is stream should be the outputstream from the request & switch output buffering off.
Couple this with outputcaching and you reduce the memory load on the server.
Simon
You can use this as source form the image.
src="data:image/jpg;base64,<%= System.Convert.ToBase64String(result["PHOTO"] as byte[]) %>"

JSON WebService in ASP.NET

How do I create an ASP.NET web service that returns JSON formatted data?
The most important thing to understand is to know how to represent data in JSON format.
Please refer http://www.json.org/ to know more about it.
Once you understand this, then the rest part is pretty straight forward.
Please check the following URL for an example of the same.
http://www.ajaxprojects.com/ajax/tutorialdetails.php?itemid=264
http://code.msdn.microsoft.com/JSONSampleDotNet
http://www.phdcc.com/xml2json.htm
I recommend Jquery library for this. It's a lightweight rich library which supports calling web services, handle json data format output etc.
Refer www.jquery.com for more info.
.NET 3.5 has support built-in. For .NET 2.0, extra libraries are needed. I used the Jayrock library.
I recently delivered an application that uses pure Javascript at the browser (viz. using AJAX technology, but not using Microsoft AJAX or Scriptaculous etc) which marries up to Microsoft webservices at the back end. When I started writing this I was new to the world of .NET, and felt overwhelmed by all the frameworks out there! So I had an urge to use a collection of small libraries rather than very large frameworks.
At the javascript application, I call a web service like this. It directly reads the output of the web service, cuts away the non JSON sections, then uses https://github.com/douglascrockford/JSON-js/blob/master/json2.js to parse the JSON object.
This is not a standard approach, but is quite simple to understand, and may be of value to you, either to use or just to learn about webservices and JSON.
// enclosing html page has loaded this:
<script type="text/javascript" src="res/js/json2.js"></script>
// Invoke like this:
// var validObj = = callAnyWebservice("WebServiceName", "");
// if (!validObj || validObj.returnCode != 0) {
// alert("Document number " + DocId + " is not in the vPage database. Cannot continue.");
// DocId = null;
// }
function callAnyWebservice(webserviceName, params) {
var base = document.location.href;
if (base.indexOf(globals.testingIPaddr) < 0) return;
gDocPagesObject=null;
var http = new XMLHttpRequest();
var url = "http://mywebserver/appdir/WebServices.asmx/" + webserviceName;
//alert(url + " " + params);
http.open("POST", url, false);
http.setRequestHeader("Host", globals.testingIPaddr);
http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
http.setRequestHeader("Content-Length", params.length);
// http.setRequestHeader("Connection", "close");
//Call a function when the state changes.
http.onreadystatechange = function() {
if (http.readyState == 4 ) {
if (http.status == 200) {
var JSON_text = http.responseText;
var firstCurlyQuote = JSON_text.indexOf('{');
JSON_text = JSON_text.substr(firstCurlyQuote);
var lastCurlyQuote = JSON_text.lastIndexOf('}') + 1;
JSON_text = JSON_text.substr(0, lastCurlyQuote);
if (JSON_text!="")
{
//if (DEBUG)
// alert(url+" " +JSON_text);
gDocPagesObject = eval("(" + JSON_text + ")");
}
}
else if (http.readyState == 4)
{alert(http.readyState + " " + http.status + " " + http.responseText)}
}
}
http.send(params);
if (gDocPagesObject != null) {
//alert(gDocPagesObject.returnCode + " " + gDocPagesObject.returnString);
return gDocPagesObject;
}
else
return "web service unavailable: data not ready";
}
In our project the requirements were as follow -- ASP.NET 2.0 on the server, and pure Javascript on the browser (no JQuery libs, or .NET AJAX)
In that case on the server side, just mark the webmethod to use JSON. Note that both input and output params are json formatted
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public String Foo(String p1, String p2)
{
return "Result: p1= " + p1 + " p2= " + p2;
}
On the javascript side, use the regular XmlHttpRequest object, make sure you format your input params as JSON and do an 'eval' on output parms.
var httpobj = getXmlHttpRequestObject();
//Gets the browser specific XmlHttpRequest Object
function getXmlHttpRequestObject()
{
if (window.XMLHttpRequest)
return new XMLHttpRequest();
else if(window.ActiveXObject)
return new ActiveXObject("Microsoft.XMLHTTP");
}
CallService()
{
//Set the JSON formatted input params
var param = "{'p1' : 'value1', 'p2' : 'value2'}";
//Send it to webservice
if(httpobj.readyState == 4 || httpobj.readyState == 0)
{
httpobj.open("POST", 'service.asmx/' + 'Foo', true);
//Mark the request as JSON and UTF-8
httpobj.setRequestHeader('Content-Type','application/json; charset=utf-8');
httpobj.onreadystatechange = OnSuccess;
httpobj.send(param);
}
}
OnSuccess()
{
if (httpobj.readyState == 4)
{
//Retrieve the JSON return param
var response = eval("(" + httpobj.responseText + ")");
}
}

Resources