Catch too long form submission - javascript

I am developing an HTML page which has simple HTML form (nothing special) being submitted by button. There is a couple of situations when form submitted and response comes too long (if whenever really comes back). How can i organize the form the way it fires some callback when waiting a response is too long? We could show up some notice for user, indicating our server is overloaded in that situation.
Here is request that being sent by form:
POST http://example.com/search HTTP/1.1
Host: example.com
Proxy-Connection: keep-alive
Content-Length: 83
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: http://example.com
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://example.com/
Accept-Encoding: gzip, deflate
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: [cookie definition omitted]
[form data omitted]
Is Proxy-Connection: keep-alive influence the process somehow? Googling led me to https://github.com/caxap/jquery-safeform plugin, but it is for a little bit different purpose.

It depends on what type of UI you want to present to the user. You can simply lower the timeout at the server level and if it can't finish the response in time, it will abort. However, the user experience is pretty harsh, as they'll just get a generic timeout error that likely won't even be from your site. (They'll have to click back or something to get back to your site.)
If you just want to display a message after a certain amount of time has passed, you can attach to the form's submit event and use setTimeout to display an alert or something:
$('#MyForm').on('submit', function () {
setTimeout(30000, function () { // number is milliseconds
alert('Sorry this is taking so long.');
});
});
Finally, if there's some method of tracking the progress of the action that's being completed server-side, you could use something like web sockets or long-polling via AJAX to provide a progress bar or status update of some sort. That's a bit more complex, though, and will require some research on your part.

There are two approaches, I will write two separate answers.
XMLHttpRequest progress approach
(for modern browsers)
Just send data and read uploading progress from XMLHttpRequest:
//-------------upload ------------------
var lastProgressIndex = -1;
//is the file api available in this browser
//only override *if* available.
if (new XMLHttpRequest().upload) {
$("#upload-files").click(function () {
upload_files($("#files-to-upload")[0].files, lastProgressIndex++);
return false;
});
$("#files-to-upload").change(function () {
upload_files($("#files-to-upload")[0].files, lastProgressIndex++);
return false;
});
$("#upload-files").hide();
}
function resetFormElement(elem) {
elem.wrap('<form>').closest('form').get(0).reset();
elem.unwrap();
}
function clear_upload() {
//https://stackoverflow.com/questions/1043957/clearing-input-type-file-using-jquery
var upload = $("#files-to-upload");
//upload.replaceWith(upload = upload.clone(true));
resetFormElement(upload);
}
//accepts the input.files parameter
function upload_files(filelist) {
if (typeof filelist !== "undefined") {
for (var i = 0, l = filelist.length; i < l; i++) {
upload_file(filelist[i], lastProgressIndex++);
}
}
clear_upload();
}
//each file upload produces a unique POST
function upload_file(file, index) {
//TODO - vytvor progress bar podle indexu
$("#progresscontainer").append('<div id="progressbar' + index + '" class="progressbar"><div id="progresslabel' + index + '" class="progressbarlabel"></div></div>')
var progressBarSelector = "#progressbar" + index;
var progressLabelSelector = "#progresslabel" + index;
var fileName = file.name;
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
//update the progress bar
var percent = Math.floor((evt.loaded / evt.total) * 100) + "%";
//TODO http://www.binaryintellect.net/articles/859d32c8-945d-4e5d-8c89-775388598f62.aspx
$(progressBarSelector).css({
width: percent
});
$(progressLabelSelector).html(fileName + ' ' + percent);
}
}, false);
// File uploaded
xhr.addEventListener("load", function () {
$(progressLabelSelector).html(fileName + " uploaded");
AddImageToGallery(GetFilenameWithoutExt(fileName));
$(progressBarSelector).fadeOut(500, function () {
$(progressBarSelector).remove();
});
}, false);
var guid = $("#Identification").val();
xhr.open("post", "/uploadurl/uploadfile/" + guid, true);
// Set appropriate headers
// We're going to use these in the UploadFile method
// To determine what is being uploaded.
xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.setRequestHeader("X-File-Name", file.name);
xhr.setRequestHeader("X-File-Size", file.size);
xhr.setRequestHeader("X-File-Type", file.type);
// Send the file
xhr.send(file);
}
And server part:
private UploadedFile[] RetrieveFileFromRequest()
{
List<UploadedFile> uploadedFiles = new List<UploadedFile>();
if (Request.Files.Count > 0)
{ //they're uploading the old way
for (int i = 0; i < Request.Files.Count; i++)
{
var file = Request.Files[0];
string contentType = file.ContentType;
string filename = file.FileName;
UploadedFile uploadedFile = SaveUploadedFile(file.InputStream, file.ContentLength, filename, contentType);
uploadedFiles.Add(uploadedFile);
}
}
else if (Request.ContentLength > 0)
{
string filename = Request.Headers["X-File-Name"];
string contentType = Request.Headers["X-File-Type"];
UploadedFile uploadedFile = SaveUploadedFile(Request.InputStream, Request.ContentLength, filename, contentType);
uploadedFiles.Add(uploadedFile);
}
return uploadedFiles.ToArray();
}
These sources are modification of the original article. There is related stackoverflow question.

How can I organize the form the way it fires some callback when waiting a response is too long?
This is based on your algorithm. You can estimate the time like brute force calculation and show the result before beginning to perform. It's not an optimized solution if you start processing and then break it when too many time is spent!
Update: If you can't estimate like above, At least, write an asynch controller method which is useful when an action must perform several independent long running operations. Follow this:
Write an Ajax Form with unobtrusive-ajax
Define a function for OnBegin form option to call a timer
The timer's time out event will show another thing to user.
Write an asynch controller method for the operation which
contains a timer to stop processing when it takes more
than ?? seconds.

There are two approaches, I will write two separate answers.
Sending thread/UI thread approach
You will need 2 javascript "threads".
Sending thread:
With first open websocket and start sending data to server. On the server side update some variable how many data was sent and how many remaining.
UI thread:
Using Ajax ask server frequently (HTTP request with JSON format is fine), how many data was send and how many remaining and render the progressbar in javascript.
Finnaly, when UI thread request receive information that upload is ready, remove progressbar with jquery and show message or redirect page.
With this approach you can easily show send bytes, estimation time remaining, upload speed.
So every javascript thread has corresponding server tread. And both server threads share the structure with dataSend and dataRemaining dependent on your server technology.
Bellow You can find part of my code which upload several images and show preview after finish is finished:
intervalID = window.setInterval(function()
{
var request = new Sys.Net.WebRequest();
request.set_url('UploadProgress.ashx?DJUploadStatus=' + token + '&ts=' + new Date().getTime());
request.set_httpVerb('GET');
request.add_completed(function(executor) {
// the progress is returned as xml
var e = executor.get_xml().documentElement;
var empty = e.getAttribute('empty');
if (!empty)
{
// extract the attributes I am interested in
var percent = e.getAttribute('progress');
var file = e.getAttribute('file');
var kbs = Math.round(parseInt(e.getAttribute('bytes')) / 1024);
var size = Math.round(parseInt(e.getAttribute('size')) / 1024);
// update the progressbar to the new value
progressBar.set_percentage(percent);
// upadte the message
updateMessage('info', 'Uploading ' + file + ' ... ' + kbs + ' of ' + size + ' KB');
if (percent == 100)
{
// clear the interval
window.clearInterval(intervalID);
}
}
});
// invoke the request
request.invoke();
}, 1000);

You could check for WebTimeout exception from server side then use SignalR to actively send timeout messsage back to client side:
var request = (HttpWebRequest)WebRequest.Create("http://www.your_third_parties_page.com");
request.Timeout = 1000; //Timeout after 1000 ms
try
{
using (var stream = request.GetResponse().GetResponseStream())
using (var reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
}
catch (WebException ex)
{
//Check for timeout exception
if (ex.Status == WebExceptionStatus.Timeout)
{
//If timeout then send SignalR ajax message to inform the clients...
var context = GlobalHost.ConnectionManager.GetHubContext<YourHub>();
context.Clients.All.addNewMessageToPage("This method has been processing too long!");
}
}
See more how to setup SignalR for asp.net here

Related

How can I get Text from Js to Python

<script>
function voice(){
var recognition = new webkitSpeechRecognition();
recognition.lang = "en-GB";
recognition.onresult = function(event){
console.log(event);
document.getElementById("speechto").value = event.results[0][0].transcript;
}
recognition.start();
}
</script>
I am making language translator web-app. And in above code, it takes input from the user using mic and print that in textarea in eng language. So I want this text in my python so that I can translate it and print it on another textarea. But i dont know how can I get that text from the js into my python code.
any soln?
Where is "your python"? I'm assuming this is on a browser over a network. You gotta set up a webserver (in python) to listen to network responses. Try webpy for a simple solution: https://webpy.org/.
You'll have to set up a URL endpoint to respond to POST requests. More info here: https://webpy.org/docs/0.3/tutorial#getpost.
And lastly, you'll have to set up your Javascript to send the post request and to use the response from your server to edit the textarea. You can use the JS fetch API to send the post request and handle the response from there.
Good luck hooking everything up
I assume you're using flask as that is tagged in your question. You need to establish a route to execute your python code and run your flask app which should listen to some TCP port on your computer (by default flask seems to use port 5000).
Then on your js code you can use the fetch method to send the text to that port. For example:
fetch('http://locahost:5000/{your flask route goes here}', {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
},
body: {text you want to send goes here},
})
rather than using python just to do a translation, why not to use a simple javascript translate function?
var translate = async (t,src,dst) => {
var tt = new Promise(function(resolve) {
var i=0, len=0, r='', tt='';
const url = 'https://clients5.google.com/translate_a/';
var params = 'single?dj=1&dt=t&dt=sp&dt=ld&dt=bd&client=dict-chrome-ex&sl='+src+'&tl='+dst+'&q='+t;
var xmlHttp = new XMLHttpRequest();
var response;
xmlHttp.onreadystatechange = function(event) {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
response = JSON.parse(xmlHttp.responseText);
for (var i = 0, len = response.sentences?.length; i < len; i++) {
var r=(((response.sentences[i].trans).replace('}/g','')).replace(')/g','')).replace('\%20/g', ' ');
r=((r.replace('}','')).replace(')','')).replace('\%20/g', ' ');
tt += r;
}
if (tt.includes('}'||')'||'%20')) {
tt=((tt.replace('}/g','')).replace(')/g','')).replace('\%20/g', ' ');
}
resolve(tt);
}
}
xmlHttp.open('GET', url+params, true);
xmlHttp.send(null);
xmlHttp.onreadystatechange();
});
return await tt;
}

How can I monitoring and intercepting all dynamic AJAX Requests and resend them again?

How can I monitoring and intercepting all dynamic AJAX Requests and resend them again?
How can I do this?
XMLHttpRequest.prototype.realSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(value) {
this.addEventListener("error", function(){
/*
Need Resend It By XMLHttpRequest In Here
All Resend Request Are Dynamic Generate
Such As "new XMLHttpRequest(this).send()"
Use AJAX Are Also OK
*/
}, false);
this.realSend(value);
};
Try the following. Obviously it will work for AJAX calls made after the execution of this snippet, so you will need to execute it as soon as possible.
I don't know exactly what is your use case, but be aware that a failed request can fail 1 million more times if the cause of the error is not fixed. With this code each retry is equal to the previous failed one.
Please also note that you will need to make some modifications to access the response of a nested request once successful.
// PROXY 'open' INSTEAD OF 'send' SO YOU CAN CAPTURE REQUESTS EARLY.
XMLHttpRequest.prototype._open = XMLHttpRequest.prototype.open;
// WE NEED TO TRACK RETRY NUMBER PER REQUEST TO AVOID INFINITE LOOPS.
XMLHttpRequest.prototype._maxRetry = 5;
XMLHttpRequest.prototype._currentRetry = 0;
XMLHttpRequest.prototype.open = function open(...args) {
if (!this._currentRetry) {
console.log('REQUEST CAPTURED.');
}
this.addEventListener('error', () => {
// ABORT PREVIOUS REQUEST.
this.abort();
// CHECK NUMBER OF RETRIES.
if (this._currentRetry >= this._maxRetry) {
console.log('MAX RETRY REACHED.');
return;
}
console.log(`RETRYING ${this._currentRetry} of ${this._maxRetry}.`);
// CREATE NEW REQUEST INSTANCE.
const req = new XMLHttpRequest();
// COPY UPDATED RETRY NUMBERS TO NEW INSTANCE.
req._maxRetry = this._maxRetry;
req._currentRetry = this._currentRetry + 1;
req.responseType = this.responseType;
// SEND NEW REQUEST USING PREVIOUS REQUEST ARGUMENTS.
req.open(...args);
req.send();
});
// CALL ORIGINAL 'open' METHOD.
this._open(...args);
};
const test = new XMLHttpRequest();
test.open('GET', 'https://asfashdg');
test.send();

Download PDF file With FTP using XMLHttpRequest and generic handler

I am trying to download PDF file from FTP server with Jquery Ajax request. I referred http://www.dave-bond.com/blog/2010/01/JQuery-ajax-progress-HMTL5/.
My Jquery ajax call is as below
$.ajax({
xhr: function () {
var xhr = new window.XMLHttpRequest();
//Download progress
xhr.addEventListener("progress", function (evt) {
console.log("Event :"+evt.lengthComputable);
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
//Do something with download progress
console.log(percentComplete);
}
}, false);
return xhr;
},
type: 'POST',
url: "Downloader.ashx",
success: function (data) {
//Do something success-ish
}
});
And My C# generic handler code to download file is as below
public void ProcessRequest(HttpContext context)
{
DownLoadFilesFromFTp("MyFile.pdf", "Foldername");
}
public bool DownLoadFilesFromFTp(string fileName,string ftpFolder)
{
//Create FTP Request.
try
{
string Ftp_Host = System.Configuration.ConfigurationManager.AppSettings["Ftp_Host"];
string Ftp_UserName = System.Configuration.ConfigurationManager.AppSettings["Ftp_UserName"];
string Password = System.Configuration.ConfigurationManager.AppSettings["Password"];
string downloadpath= System.Configuration.ConfigurationManager.AppSettings["downloadpath"];
//Fetch the Response and read it into a MemoryStream object.
string ftpurl = Ftp_Host + ftpFolder + "/" + fileName;
FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpurl));
reqFTP.Credentials = new NetworkCredential(Ftp_UserName, Password);
reqFTP.KeepAlive = false;
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
reqFTP.Proxy = null;
reqFTP.UsePassive = false;
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream writeStream = null;
//if (fileName.Substring(fileName.Length - 3, 3) == "pdf" || fileName.Substring(fileName.Length - 3, 3) == "PDF")
//{
writeStream = new FileStream(downloadpath + fileName, FileMode.Create);
//}
int Length = 2048; // 2048;
Byte[] buffer = new Byte[Length];
int bytesRead = responseStream.Read(buffer, 0, Length);
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, Length);
}
responseStream.Close();
writeStream.Close();
response.Close();
return true;
}
catch (WebException wEx)
{
return false;
}
catch (Exception ex)
{
return false;
}
}
When I run a code files downloads to a folder without any issues and on Ajax call
if (evt.lengthComputable) {
}
When I console evt i got below result
Always returns false so i am unable to track a progress.
1) is there anything wrong with the code ?
2) Any alternative way to show progress bar while downloading pdf
For the bytes uploaded, it is quite easy to show progress bar. Just monitor the xhr.upload.onprogress event. The browser knows the size of the files it has to upload and the size of the uploaded data, so it can provide the progress info.
For the bytes downloaded, it is a little bit more difficult, because the only thing that the browser knows in this case is the size of the bytes it is receiving.
The reason of evt.lengthComputable is 0 is that the browser doesn't
know how many bytes will be sent in the server request.
There is a solution for this, it's sufficient to set a Content-Length header on the server like below, in order to get the total size of the bytes the browser is going to receive.
// prepare the response to the client. resp is the client Response
var resp = HttpContext.Current.Response;
// Add Content-Length of the file to headers
// if the headers is not set then the evt.loaded will be 0
resp.AddHeader("Content-Length", "lengthOfYourFile");
Your code JS side look fine.
I am not C# programmer, but i observed that C# server side, download the file ftp and save it to disk server, but never response/send the PDF binary to JS SIDE?
From JS side is 0 bytes download. and evt.lengthComputable is alway false/0.

post xml as a binary file using javascript

I'm trying to write something that can post xml, as a binary file to an external URL (which I have no control over) in JavaScript.
I have YUI3 available to me. And probably jQuery if I needed it.
Any ideas? Everything I've looked at seems to be about receiving xml, rather than posting it.
Edit: The external url is an advertising bot, the xml essentially describes what sort of ad I want to get back.
I'm forced to post as binary. I've tested using-
<form enctype="multipart/form-data" action="http://something.com" method="post">
<input name="anything" type="file">something</file>
<input type="submit">
</form>
and that works. I just need to implement in js.
Edit #2
My solution (couldn't get it formatted properly)-
var AdManager = {
getRandomBoundary : function(){
var today = new Date;
return '---' + today.getTime();
},
fetch : function(){
var boundary = this.getRandomBoundary();
var xhr = new XMLHttpRequest;
var CRLF = "\r\n";
xhr.open('POST', 'http://url.com', true);
xhr.onreadystatechange = function(){
if (xhr.readyState === 4)
{
//Parse xml(badly)
var splitter = xhr.responseText.split('<responsecontent>');
var allAds = '';
for (var i= 1; i< splitter.length; i++)
{
var tempAd = splitter[i].split('</responsecontent>');
allAds += tempAd[0];
}
//Html is returned encoded, so decode.
jQuery('#results').html(jQuery("<div/>").html(allAds).text());
}
};
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
var mimeReq = "--" + boundary + CRLF;
mimeReq += 'Content-Disposition: form-data; name="arbitrary"; filename="arbitrary.xml"' + CRLF;
mimeReq += 'Content-Type: application/octet-stream' + CRLF + CRLF;
mimeReq += '<?xml version=\"1.0\" encoding=\"utf-8\"?><adrequestpacket responsemarkup=\"wml\" test=\"0\" xmlns=...'+ CRLF;
mimeReq += "--" + boundary + "--" + CRLF;
xhr.send(mimeReq);
}
};
`
I think I understand what your asking, but if I'm totally on the wrong track, the below may appear a little patronising, so apologies in advance...
If all you want to do is send an XML file to a known URL via AJAX its fairly simple in javascript with no lovelies like jQuery etc. I am assuming you have already generated the XML file and have it stored as string variable somewhere.
The below code is a bit messy and fairly basic, but hopefully it should point you in the right direction. There are probably better ways of fetching an AJAX object if you search for them, but this is a method I have used for ages and never really have any problems with.
You will need to write some code to parse the server response to determine whether data was accepted or not - see comments in code for where you would do this. The ajaxObj.status and ajaxObj.responseText properties will be your friends here.
function postXMLToServer (serverURL, xmlStr) {
// Declare some variables
var activeXModes, i, ajaxObj, aSync, contentType;
// Set this to false to perform the request synchronously (i.e. execution will block until request has completed)
aSync = true;
// 'application/octet-stream' is treated as raw binary data by any sensible server.
// It might make more sense to use 'text/xml' or some variant depending on your application
contentType = 'application/octet-stream';
// Fetch an AJAX object
activeXModes = ["Msxml2.XMLHTTP","Microsoft.XMLHTTP"];
if (window.ActiveXObject) { // Try ActiveX (for IE)
for (i = 0; i < activeXModes.length; i++) {
try {
ajaxObj = new ActiveXObject(activeXModes[i]);
} catch (e) {}
}
} else if (window.XMLHttpRequest) { // For Mozilla, Safari etc
ajaxObj = new XMLHttpRequest();
} else { // No AJAX
alert('AJAX is not supported in your browser');
return;
}
// Open connection to server
ajaxObj.open('POST',serverURL,aSync);
// Set some request headers - you might be able to get away with not doing this, but it
// should be considered good practice, especially when doing POST requests
ajaxObj.setRequestHeader('Content-Type',contentType);
ajaxObj.setRequestHeader('Content-Length',xmlStr.length);
// Set a callback for asynchronous requests (not called if aSync = false)
ajaxObj.onreadystatechange = function () {
if (ajaxObj.readyState == 4) {
// parse the server response here
}
};
// Send the request
ajaxObj.send(xmlStr);
// if aSync = false, parse the server response here
}
// Example of how to use the function
var myXMLStr = '<?xml version="1.0" encoding="iso-8859-1" ?>\n<toplevel>\n<lowerlevel anattribute="a value">An inner value</lowerlevel>\n</toplevel>';
var myURL = 'http://sub.domain.tld/path/to/document.ext?getparameter=somevalue';
postXMLToServer(myURL,myXMLStr);
It's not entirely clear what you want. Everything in the computer is represented in binary. So when you post an XML document over to http://something.com, the it's the binary representation of the characters in the XML file that is being transmitted.

Using XHR to send large amounts of data via POST

I have an XHR that uploads large amounts of data to the server. This XHR dies intermittently and seemingly without pattern. Currently my code looks like this:
function makeFormData(data) {
var formdata = "";
for (var key in data) {
formdata = formdata + "&" + key + "=" + encodeURIComponent(data[key]);
}
return formdata.slice(1);
}
function xhr(url, data, onsuccess, onerror) {
var xhrequest = new XMLHttpRequest();
xhrequest.onreadystatechange = function () {
if (xhrequest.readyState != 4)
return;
if (xhrequest.responseText)
onsuccess(xhrequest.responseText);
}
xhrequest.onerror = function (error_param) {
onerror(error_param);
}
xhrequest.open('POST', url, true);
xhrequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhrequest.send(makeFormData(data));
}
This is in a Chrome extension. What am I doing wrong? How can I make the form multipart instead, to make the upload smaller? I have used Wireshark to trace the request and the it cuts off mid-send with many packet retransmissions (and never completes).
Please help me, this is driving me crazy.
check the server directives. Maybe the max_execution_time and upload size have tiny values. If the js don't perform request try debug it.

Categories