ASP.NET XMLHTTPREQUEST download file using Handler - asp.net

am trying to implement file download using xmlhttprequest... But am not getting the file dialog or any response. I have debug the handler, no error.
function download(id)
{
try
{
var xmlHttp=new XMLHttpRequest();
xmlHttp.open("GET","DownloadFileHandler.ashx?id=" + id,false);
xmlHttp.send();
xmlHttp.onreadystatechange=function()
{
//if request has been entertained and response is returned from server
if(xmlHttp.readyState==4)
{
alert("aq");
}
}
}
catch (ex)
{
alert("Browser does not support ajax");
}
}
}
my handler
context.Response.AppendHeader("content-disposition", "attachment; filename=" + name);
context.Response.ContentType = type;
context.Response.WriteFile(path);
context.Response.End();

So, clearly AJAX uses a XML based http requests. This is a different
protocol than a file download request. A file download is a binary
http request.
First, while the XmlHttpRequest object can parse the data to XML, you can also get the full data, be it binary or not. You can parse it into whatever you want.
Second, it is not a different protocol. The protocol is HTTP. HTTP is transferring the data, and doing content negotiation, in both cases.
Third, HTTP GET requests (the same kind of request in both cases) can return binary or textual data entirely independent on how the request is generated. A request can be generated through an tag, or a user clicking an link, or an XMLHttpRequest, and the content type (binary or text) is totally independent of how the request was generated.
The real reason you can't download a file using XMLHttpRequest, but instead have to use browser-specific extensions such as nsIWebBrowserPersist, is that browsers have chosen to not pay attention to the Content-Disposition header when reading data returned from an XMLHttpRequest, the way they do when reading data for a top-level page (or -- you can trigger a download by getting data through an invisible iframe)
Personally, I think this is a poor choice by web browsers, because there is no extra security, only inconvenience for developers. There's no way to send Accept: headers or verbs other than GET by issuing requests with an IFRAME or IMG element, so you can't control content negotiation. Instead, you have to escape the HTTP protocol into GET parameters, which I find sad and un-REST-ful.
For more information on nsIWebBrowserPersist, see https://developer.mozilla.org/en/Code_snippets/Downloading_Files

Notice in your code you have:
var xmlHttp=new XMLHttpRequest();
So, clearly AJAX uses a XML based http requests. This is a different protocol than a file download request. A file download is a binary http request.
Kinda like speaking two different languages when there is no translator. Doesn't work...
So, one solution is to create a link which points to a .ashx handler which can get the file and send it to the client

Related

Is there a way to set the http Header values for an esp_https_ota call?

I'm trying to download a firmware.bin file that is produced in a private Github repository. I have the code that is finding the right asset url to download the file and per Github instructions the accept header needs to be set to accept: application/octet-stream in order to get the binary file. I'm only getting JSON in response. If I run the same request through postman I'm getting a binary file as the body. I've tried downloading it using HTTPClient and I get the same JSON request. It seems the headers aren't being set as requested to tell Github to send the binary content as I'm just getting JSON. As for the ArduinoOTA abstraction, I can't see how to even try to set headers and in digging into the esp_https_ota functions and http_client functions there doesn't appear to be a way to set headers for any of these higher level abstractions because the http_config object has no place for headers as far as I can tell. I might file a feature request to allow for this, but am new to this programming area and want to check to see if I'm missing something first.
Code returns JSON, not binary. URL is github rest api url to the asset (works in postman)
HTTPClient http2;
http2.setAuthorization(githubname,githubpass);
http2.addHeader("Authorization","token MYTOKEN");
http2.addHeader("accept","application/octet-stream");
http2.begin( firmwareURL, GHAPI_CERT); //Specify the URL and certificate
With the ESP IDF HTTP client you can add headers to an initialized HTTP client using function esp_http_client_set_header().
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_set_header(client, "HeaderKey", "HeaderValue");
err = esp_http_client_perform(client);
If using the HTTPS OTA API, you can register for a callback which gives you a handle to the underlying HTTP client. You can then do the exact same as in above example.

Binary data in body is corrupted when sending HTTP POST in JMeter

I have a local web app with an HTTP POST endpoint.
This endpoint receives emails sent from SendGrid.
I have saved the body of a previous email with attachments which I know works, as requestBody.bin.
I'm trying to replicate this HTTP POST request using JMeter.
I have this Beanshell Preprocessor script:
FileInputStream in = new FileInputStream("C:\\Projects\\centaurjmeter\\src\\InboundEmails\\requestBody.bin");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[999024]; //Value of Content-Length from when I sent the actual email. So this should be more than enough just for the HTTP POST body.
for (int i; (i = in.read(buffer)) != -1; ) {
bos.write(buffer, 0, i);
}
in.close();
byte[] requestBody = bos.toByteArray();
bos.close();
vars.put("requestBody", new String(requestBody, "ISO-8859-1"));
and I'm using ${requestBody} in the body of the HTTP POST request:
This is what my JMeter test looks like:
In my HTTP POST action method, I'm saving the attachments of the email to file.
The pdfs seem to be slightly corrupted, only part of the text on each page is showing.
The .png files do not even open.
I've tried using:
vars.put("requestBody", new String(requestBody));
vars.put("requestBody", new String(requestBody, "Windows-1252")); //ANSI
vars.put("requestBody", new String(requestBody, "ISO-8859-1")); //default encoding
But none of them work. "ISO-8859-1" results in the least amount of corruption, in that at least some text appears in the pdfs (but the .png files don't work at all).
I can't use a HTTP Raw Request Sampler because that doesn't work with https.
How can I get the bytes from requestBody.bin and send them in my HTTP POST body correctly?
UPDATE
I read https://stackoverflow.com/a/41892324/2063755 and tried sending requestBody.bin as a file with the request in the "Files Upload" tab, but I get the same result as using the Beanshell Preprocessor script.
UPDATE
The above link actually did help me solve the problem.
I just had to add this extra TE header:
You need to ensure that the same encoding is being applied everywhere, I would recommend sticking to UTF-8
Run JMeter providing file.encoding=UTF-8 property, it can be added to system.properties file (lives in "bin" folder of your JMeter installation)
Since JMeter 3.1 you should be using JSR223 Test Elements and Groovy language for scripting so you can use the following __groovy() function directly in the "Body Data" tab of your HTTP Request sampler:
${__groovy(new File('C:\\Projects\\centaurjmeter\\src\\InboundEmails\\requestBody.bin').getText('UTF-8'),)}
More information on Groovy scripting in JMeter: Apache Groovy - Why and How You Should Use It
Assuming everything goes well your "local web app" should see the identical file, it can be double-checked using a 3rd-party sniffer tool like Wireshark. Make sure to use UTF-8 for parsing the file in your app as well.

Difference between downloading a web file directly & indirectly

On my web server I have a video file named 03.mp4.
I have a page (videoserver.aspx) to serve that file using below code
Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "attachment; filename=video.mp4");
Response.TransmitFile(Server.MapPath("03.mp4"));
Response.End();
Whats the difference between these 2 calls?
1: http://localhost/media/03.mp4
2: http://localhost/media/videoserver.aspx?q=03
When I point to those URLs directly in my browser, it prompts me a Save dialog in both the cases.
I have another web page that has a SWFObject. It consumes a video as input. Ok. When I feed it URL 1, it loads the video.
When I feed it URL 2, it doesn't load the video.
Why this difference? I prefer URL 2 as you can dynamically change the videos you are serving to consumers based on the query-string.
A lot of video players, including the new HTML5 <video> element, require support for so-called byte range requests using the HTTP Range header. This is normally already built in a bit self-respected HTTP server. Basically, to inform the client that the requested URL supports byte range requests, the server is supposed to return Accept-Ranges: bytes on the response and to be able to process all incoming Range requests by serving exactly the requested byte ranges back to the response as per the specification (see the first link on the Range header for detail).
So if you choose to take the HTTP response handling fully in your own hands instead of letting the HTTP server do the job it is designed for, you have to take this carefully into account.
Hence it proves I am a newbie to SWFObject.
The SWFObject I was referring to was dished out by Camtasia and it accepts a mp4 file thru FLashVars.
The question is "why did it not accept URL 2 while it accepted URL 1?". To which the answer is, URL 2 was not ending with .mp4.
And solution to my problem then was, create a handler that would accept */media/*.mp4 path and return the appropriate file's content, which in my case is fetched from DB.

Programmatically POST to ASP type WEBPAGE

I have been toiling over HttpURLConnection and setRequestProperty for 2 days so far and I cannot get this webpage to Post and return the page I desire. This is what I have so far...
...
String data = URLEncoder.encode("acctno", "UTF-8") + "=" + URLEncoder.encode("1991462", "UTF-8");
URL oracle = new URL("http://taxinquiry.princegeorgescountymd.gov");
HttpURLConnection yc = (HttpURLConnection) oracle.openConnection();
yc.setRequestMethod("POST");
yc.setRequestProperty("Content-Type", "text/html; charset=utf-8");
yc.setRequestProperty("Content-Length", "19004");
yc.setRequestProperty("Cache-Control", "private");
yc.setRequestProperty("Set-Cookie", "ASP.NET_SessionId=v5rdm145zv3jm545kdslgz55; path=/");
yc.setRequestProperty("X-AspNet-Version", "1.1.4322");
yc.setRequestProperty("X-Powered-By", "ASP.NET");
yc.setRequestProperty("Server", "Microsoft-IIS/6.0");
yc.setDoOutput(true);
yc.setDoInput(true);
OutputStreamWriter out = new OutputStreamWriter(yc.getOutputStream());
out.write(data);
out.flush();
//out.write(data);
out.close();
...
It returns the same page defined in URL. it doesn't send me the requested page which should have an ending /taxsummary.aspx
It looks as if the asp takes the post data and generates an HTML unique for each parameter given. How do I give it the correct parameters?
Your code looks fine. I believe it sends POST correctly. I think that the problem is not here. When you are using browser you first perform at least one HTTP GET to arrive to the form. When you are doing this the server creates HTTP session for you and returns its id in response header Set-Cookie. When you are submitting the form using browser it sends this header (Cookie) back, so the server can identify the session.
When you are working from java you are skipping the first phase (HTTP GET). So the first thing you are doing is POST while you do not have session yet. I do not know what is the logic of this ASP page but I think that it just rejects such requests.
So, first check this guess. You can use plugin to Firefox named LiveHttpHeaders. Install it and perform the operation manually. You will see all HTTP requests and responses. Save them. Check that the session ID is sent back from server to client. Now implement exactly the same in java.
BTW often the situation is event more complicated when server sends multiple redirect responses. Int this case you have to follow them. HttpConnection has method setFollowRedirects(). Call it with parameter true.
BTW2: Apache HttpClient is a perfect replacement to HttpConnection. it does everything and is very recommended when you are implementing such tasks.
That's all. Good luck. Sometimes it is not easy...

Sending Zip file to Client via Response - incorrect type being sent

OK, I've been pulling my hair out about this for ages. I have a WebService which sends a zip file to the browser. This works; when I test the WebService and 'invoke' the method through it directly, the zip file is downloaded to the browser correctly.
The problem arises when I use jQuery to send an AJAX request to the WebService - the zip file is downloaded to the response, but it stays in the response and doesn't download as a file.
Here is my code:
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ContentType = "application/zip";
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=pleasework.zip");
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory("c:\\inetpub\\mediaserver\\music\\mixes");
zip.AddFile("c:\\test.txt");
zip.AddFile("c:\\test2.txt");
zip.Save("c:\\filename.zip");
}
HttpContext.Current.Response.TransmitFile("c:\\iloveshrooms.zip");
return "done";
}
Now this works since the file downloads when I use the 'invoke' function when navigating directly to the service.
Here is my jQuery AJAX request...
function getFile() {
alert("sending POST request...");
$.ajax({
type: 'POST',
url: 'ZipService.asmx/GetZipFile HTTP 1.1',
contentType: "application/x-www-form-urlencoded",
data: '{ "path":"c:\\inetpub\\mediaserver\\music\\mixes" }',
dataType: '',
beforeSend: function(xhr) {xhr.setRequestHeader("Accept","application/zip");},
success: function() {alert(":-)");},
failure: function() {alert(":-(");}
});
}
I added the code in 'beforeSend' so that the request states explicitly what type of response the browser should expect.
I've been using Firebug to monitor the request/response headers and can't see anything wrong with them (except when I look at the content of the response, it's full of binary data AND its the same size as the file I'm sending.
I just attempted to upload screen-dumps of the request/response headers and the content of the reponse but I don't have enough reputation points to do this yet :-(
The Response is the same size of the Zip file so I'm assuming its being sent back to the browser, but the browser doesn't know what to do with it.
Tested in IE, FF & Chrome and the results are consistent.
If anyone could shed any light on this I'd greatly appreciate it!
There are a couple of easy solutions.
Convert your server procedure to use a GET request, you can use window.open, to initialize the download.
window.open('your_procedure_url?parameter=xyz')
If you want stick with POST, you can create a hidden form, with inputs for each of the parameters. Set the form action to POST to your service url and use form.submit() to launch the download.
1st. Don't make it a webservice. If it always delivers a zip file, why is it not an aspx or a ashx? A resource that is requested by a script, need not be an ASMX.
2nd. it's not true that you cannot receive a binary file in AJAX or javascript. You can. For example, see Unzipping zip archives with Javascript.
But make sure you actually want to handle the zip file in script. In most cases you want to let the user save the zip file to the filesystem.

Resources