Plupload crossdomain upload 200 http error - html

I would like to upload files to a remote server using the plupload library. Everything works with Chrome (32.0) and IE 10 using the html5 runtime but when I try with Firefox 27 (html5 runtime) or IE 8 (html4 runtime) I get an error Error #-200: HTTP Error..
Clientside script :
$(function() {
var uploader = new plupload.Uploader({
browse_button: 'browse',
url: 'https://remote.com/API/action.php',
runtimes : 'html5,flash,silverlight,html4',
flash_swf_url : './js/Moxie.swf',
silverlight_xap_url : './js/Moxie.xap'
});
uploader.init();
uploader.settings.multipart_params = {
[...]
};
// PreInit events, bound before any internal events
uploader.bind('init', function(up, info) {
console.log('[Init]', 'Info:', info, 'Features:', up.features);
alert(info['runtime']);
});
uploader.bind('Error', function(up, err) {
document.getElementById('console').innerHTML += "\nError #" + err.code + ": " + err.message;
});
document.getElementById('start-upload').onclick = function() {
uploader.start();
};
});
First request with Chrome :
Request URL:https://remote.com/API/action.php
Request Method:OPTIONS
Status Code:200 OK
Second request with Chrome :
Request URL:https://remote.com/API/action.php
Request Method:POST
Status Code:200 OK
Request Headers
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host:hipt.ucc.ie
Origin:http://server.com
Pragma:no-cache
Referer: XXX
User-Agent:Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36
Response Headers
Access-Control-Allow-Headers:Content-Type, Authorization, X-Requested-With
Access-Control-Allow-Methods:GET, PUT, POST, DELETE, OPTIONS
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1000
Cache-Control:no-cache
Connection:close
Content-Length:5
Content-Type:text/html; charset=UTF-8
Date:Mon, 24 Feb 2014 11:57:54 GMT
Server:Apache/2.2.3 (CentOS)
X-Powered-By:PHP/5.1.6
Serverside script :
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
header('Cache-Control: no-cache');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
if (!empty($_FILES)) {
With Firefox the response to the request with the OPTIONS method is empty and there is no following POST request.
Here are the Firefox headers:
I cannot figure out why it is not working with Firefox and IE8.
Thanks for your help.
[EDIT] I just tried with flash runtimes: same thing it works with Chrome and IE 10 but not with Firefox and IE8. The weird thing is that the alert(info['runtime']); does not appear but there is no javascript error in the console...

Ok so I finally find out why it wasn't working. I checked using wireshark and I noticed that there was an encrypted alert.
I then check the certificate of the remote server using : http://www.sslshopper.com/ssl-checker.html and got this answer :
The certificate is not trusted in all web browsers. You may need to install an Intermediate/chain certificate to link it to a trusted root certificate. Learn more about this error. The fastest way to fix this problem is to contact your SSL provider.
I had to add an exception and it finally worked \o/

This error is also raised when you get a server-side 500 error. For example, if you have a syntax error in your program (or a fatal run-time error).

I had the same problem, but I clearly knew that the problem was in csrf token.
The solution is the following:
HTML:
<HTML>
<body>
<p>your template content</p>
<!-- upload demo -->
<ul id="filelist"></ul>
<br />
<pre id="console"></pre>
<div id="container">
<a id="browse" href="javascript:;">[Browse...]</a>
{% csrf_token %} <!-- it may be places elsewhere in HTML -->
<a id="start-upload" href="javascript:;">[Start Upload]</a>
</div>
<!-- upload demo end -->
<p>your template cont'd</p>
<script type="text/javascript">
// function to get your crsf token from the cookie
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const crsf = getCookie('csrftoken');
var uploader = new plupload.Uploader({
browse_button: 'browse', // this can be an id of a DOM element or the DOM element itself
url: '/upload/',
chunk_size: '822kb',
headers: {'X-CSRFToken': crsf}, // here we add token to a header
max_retries: 1
});
uploader.init();
<!-- and so on -->
</script>
</body>
</HTML>
#urls.py
urlpatterns = [
...
path(route='upload/', view=Upload.as_view(), name='upload'),
#views.py
class Upload(View):
def post(self, request):
print('got upload post request')
print(request.headers)
## do with the chunk whatever you need...
return HttpResponse('email good, thank you!', status=200)
The example from here:
https://www.plupload.com/docs/v2/Getting-Started#wiki-full-example
And you may read about settings over here:
https://www.plupload.com/docs/v2/Uploader#settings-property
It works with post() method in Django 2.1+

Related

Chrome doesn't send "if-none-match" header in HTTPS (but sends it in HTTP)

tl;dr: Chrome is not sending "If-None-Match" header for HTTPS request but sends it for HTTP request. Firefox always send "If-None-Match", both in HTTPS and HTTP.
I was trying to optimize cookies management for my node server when I came across a weird behavior with Chrome. I will try to describe it and compare it with Firefox.
First, here is the HTTP node server I'm using to test this:
#!/usr/bin/env node
'use strict';
const express = require('express');
const cors = require('cors');
const compression = require('compression');
const pathUtils = require('path');
const fs = require('fs');
const http = require('http');
let app = express();
app.disable('x-powered-by');
app.use(function (req, res, next) {
res.set('Cache-control', 'no-cache');
console.log(req.headers);
next();
});
app.use(express.json({ limit: '50mb' }));
app.use(cors());
app.use(compression({}));
let server = http.createServer(app);
app.get('/api/test', (req, res) => {
res.status(200).send(fs.readFileSync(pathUtils.join(__dirname, 'dummy.txt')));
});
server.listen(1234);
And there the client code :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
let test = fetch('http://localhost:1234/api/test', { mode: 'no-cors' })
.then((res) => {
return res.text();
})
.then((resText) => console.log(resText));
</script>
</body>
</html>
I use the header "no-cache" to force the client to re-validate the response.
If I've understood correctly how the cache work, I'm expecting client to send the request with the "If-None-Match" header having the previous request's e-tag and the server responding with a 304 code.
Here is the result when I refresh the page in Firefox (so at least one response has already be received). I embedded the server log of the request header.
Here the header "If-None-Match" is sent by the client request, as expected.
Now the same test with Chrome gives :
Well, here Chrome shows a 200 response code, but under the hood, it's really a 304 response that is sent by the server, which is shown by this wireshark capture :
As you can see, Chrome send the "If-None-Match" header with the correct e-tag, hence the 304 response.
So now, let's try this with HTTPS. In the server code, I just replaced require('http'); by require('https') and pass my ssl keys in createServer options (as described here)
So first, Firefox behaviour:
I've included the wireshark capture. And as you can see, everything is right, Firefox has the expected behaviour.
Now let's see the same thing with Chrome :
Here is my problem : as you can see, "If-None-Match" is not sent by Chrome. So as expected, the server returns a 200 response which can be seen in the wireshark capture (I refreshed the page twice, that's why there are 2 exchanges).
Do anyone have an idea on why Chrome has this weird behaviour?
I think it happened because you didn't set in your setting the certificat of your localhost.
Go to the settings and add it :)
chrome settings capture

CSP breaks Ajax-calls with "Content-Type: application/json"

I'm implementing a CSP-policy for an application.
If I try to retrieve an url with Content-Type: application/json; I get an empty "" responseText.
There is no error in console, as is is case with CSP violations.
Example ajax-call that produces an empty result, when CSP is in use:
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "/something/555.json", true);
xhttp.send();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText)
}
}
It doesn't matter, if that url produces a json-object, or text.
Neither does it depend on the contents of Content-Security-Policy header. I have tried allowing all possible directives, and just simply an empty header. Same issue with chrome, firefox and safari.
The request DOES go through to the server. And if I try to get a nonexisting page, console shows the 404 properly. Urls without .json, e.g. .html, .jsonn, .foo, or no format, produce no issues, as they generate application/text mimetype.
I'm at my wits end. CSP-documentation does not mention anything relating to json or mimetypes specifically. What am I doing wrong?
Solved. Apparently sending the CSP-headers with the json-request broke things.
For anyone else running into this: CSP-headers should not be included in ajax-responses.

How to make Web page to not wait for a response after sending a GET request

I am trying to make this web site that resides in Google Drive control a LED(on/off) via esp8266 and arduino. Partially i've succeded in doing what i want by sending to the IP of the module that communicates with the arduino a GET request witch parses it and acts accordingly. ie GET /?LED1=on HTTP/1.1
Problem is that whenever i press a button in the web site it sends the GET request and then it waits for a response from the other end (arduino),and the browser keeps loading until eather I close the connection from the arduino or I reply something like HTTP/1.1 200 OK and then close the conection.
In the first case browser shows the message that was unable to load the page and in second case it simply shows a blank page.
<DOCTYPE html>
<html>
<head>
<title>LED Control</title>
</head>
<body>
<button>LED 1 On</button>
</body>
</html>
I just want to send that LED1=on string somehow without causing the page attempt to load anything back.
A reusable solution
Modify your HTML to be something like this:
<button class="get" data-url="http://78.87.xxx.xx:333/?LED1=on">LED 1 On</button>
Now add this JavaScript:
window.onload = function () {
Array.prototype.forEach.call(document.querySelectorAll('.get'), function(el) {
el.onclick = function () {
// Use this trick to perform CORS requests too
var req = new Image();
req.src = this.dataset.url;
// The following 7 lines are completely optional
req.onload = function () {
// Was successful
};
req.onerror = function (error) {
// Encountered an error
alert('An error occurred while performing the request. + ' error);
};
};
});
};
Now any element with the class "get" when clicked, will send a request to the URL. This won't change the page either. If

xmlHttpRequest to absolute url in WP8

I have stumbled across an odd issue when testing an app in Windows Phone 8. I am using xmlHttpRequest (cannot use ajax as I need to send as bufferarray) to make a call to a third party url. This works perfectly in Android and iOS, but throws an error in WP8
Example:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function (){
if(xhr.readyState == 4){
if(xhr.status==200){
alert(xhr.responseText);
}else{
console.log("Error: "+xhr.responseText);
}
}
}
console.log("1");
xhr.timeout = 30000;
console.log("2");
xhr.open("POST","http://google.com",true);
console.log("3");
xhr.setRequestHeader("Content-Type",contentType+"; boundary=" + boundary);
console.log("4");
//other headers / auth etc
console.log("about to post");
xhr.send(bodyBuf);
this will result in:
log:"before request"
log:"1"
log:"2"
log:"Error in error callback: Cameraxxxxx = InvalidStateError"
However if I chang the open to:
xhr.open("POST","google.com",true); //or www.google.com etc
This goes right through to send, but then get a 404 status as the url is not found. I am obviously not using google in my request, but the error is the same. With "http://" it errors, but without, it doesn't error but cannot find the url.
Any thoughts appreciated.
I have found one thing, but unsure if it is related. According to W3C html 5 documentation, InvalidStateError is thown on open() if document is not fully active (when it is the active document of its browsing context). And if this is the cause of the error; how can the document not be the active document and how to I define the base url of an app that does not reside on a url (document suggests setting base to the document base url of document (or setting source origin/referrer source))?
Have gotten one step closer. After lots of fiddling about, I eventually found that for some reason on WP8 is needs the xhr to be opened before anything else is applied. So moving xhr.timeout below xhr.open sort of works.
this raises another problem in my particular case.. but that is probably another topic.
Solution for this was to move the timout to below the open.. so:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function (){
if(xhr.readyState == 4){
if(xhr.status==200){
alert(xhr.responseText);
}else{
console.log("Error: "+xhr.responseText);
}
}
}
xhr.open("POST","http://google.com",true);
xhr.timeout = 30000;
xhr.setRequestHeader("Content-Type",contentType+"; boundary=" + boundary);
//other headers / auth etc
xhr.send(bodyBuf);

can't seek html5 video or audio in chrome

I've been fiddling with the hell that is HTML5 video/audio for a couple of weeks now. Usually the reason why something failed popped up after a while, but I've been, unable to find why I get forwarding and rewinding problems in chrome.
Anyhow...
The video or audio tag is being loaded in an extjs panel when a video or audio file is requested. The files are sent as streams and they work fine in IE and firefox (after adding duration to the response header)
There's an issue with safari, but it's apparently the fact that the whole site runs in HTTPS (that's being worked on right now).
In chrome (which is my issue and is at the latest version) the video and audio loads just fine, but I'm unable to rewind or forward. When trying to seek videos just go ahead a few seconds until it reaches the end of the stream. the audio also plays just fine but trying to rewind (or forward) multiple times simply breaks the progress bar and stops the audio from playing on.
I'm not entirely sure what's being sent from the server, but I'm wondering if this might be caused by missing data in the response. If it's not that anything else to point me towards a fix is just as welcome. I think I've covered pretty much the whole set up and I've made sure that there's a source tag for each browser.
edit: this is the code generated by the javascript for one of the files:
<video width="1889" height="2" preload="auto" autoplay="1" controls="1" id="videoPlayer" style="width: 1889px; height: 233px; ">
<source src="http://localhost:8080/epaServer/epa/documents/496.ds_webm?sessionId=5616fde4-50af-43d6-a57c-f06540b64fcb" type="video/webm">
<source src="http://localhost:8080/epaServer/epa/documents/496.ds_mp4?sessionId=5616fde4-50af-43d6-a57c-f06540b64fcb" type="video/mp4">
<div>Your browser doesn't support html5 video. <a>Upgrade Chrome</a></div>
</video>
I've also found that I can't seek any of the files even if I open them separately from the application.
I've tried to find more info on my own these are the headers chrome shows in the network tab:
Request URL:https://localhost:8443/epaServer/epa/documents/496.ds_webm?sessionId=5616fde4-50af-43d6-a57c-f06540b64fcb
Request Method:GET
Status Code:200 OK
Request Headers
Accept:/
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:identity;q=1, *;q=0
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Cookie:sessionId=5616fde4-50af-43d6-a57c-f06540b64fcb
Host:localhost:8443
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.168 Safari/535.19
Query String Parametersview URL encoded
sessionId:5616fde4-50af-43d6-a57c-f06540b64fcb
Response Headers
Cache-Control:private
Content-Length:1588816
Content-Type:video/webm
Date:Mon, 14 May 2012 14:23:02 GMT
Expires:Thu, 01 Jan 1970 01:00:00 CET
Server:Apache-Coyote/1.1
X-Content-Duration:17.31
>
I found the reason why it's not working on this question:
HTML5 video will not loop
Our server doesn't understand partial content right now.
As a result chrome is sending requests for content that doesn't get answered which in turn makes our video's and audio unseekable (and unloopable).
You must handle req.headers['range'] which Chrome will send to your streaming server.
Please refer to my codes below. It worked well on Chrome, Firefox, Edge and IE. I haven't test it on Safari but hopefully it also can work.
I used Sails/Nodejs backend and gridFS/mongodb database for storing Videos files as Chunks.
try {
let foundMetaFile = await GridFS.findOne({id: fileId});
if (!foundMetaFile) return res.status(400).json(Res.error(undefined, {message: `invalid ${fileId} file`}));
let fileLength = foundMetaFile['length'];
let contentType = foundMetaFile['contentType'];
// let chunkSize = foundMetaFile['chunkSize'];
if(req.headers['range']) {
// Range request, partialle stream the file
console.log('Range Reuqest');
var parts = req.headers['range'].replace(/bytes=/, "").split("-");
var partialStart = parts[0];
var partialEnd = parts[1];
var start = parseInt(partialStart, 10);
var end = partialEnd ? parseInt(partialEnd, 10) : fileLength - 1;
var chunkSize = (end - start) + 1;
console.log('Range ', start, '-', end);
res.writeHead(206, {
'Content-Range': 'bytes ' + start + '-' + end + '/' + fileLength,
'Accept-Ranges': 'bytes',
'Content-Length': chunkSize,
'Content-Type': contentType
});
}
let { mongodbConnection } = global;
let bucket = new GridFSBucket(mongodbConnection, { bucketName: 'fs' });
return new Promise ((resolve, reject) => {
let downloadStream = bucket.openDownloadStream(fileId);
downloadStream.on('error', (err) => {
console.log("Received Error stream")
res.end();
reject(err);
})
downloadStream.on('end', () => {
console.log("Received End stream");
res.end();
resolve(true);
})
console.log("start streaming");
downloadStream.pipe(res);
})
} catch (error) {
switch (error.name) {
case 'UsageError':
return res.status(400).json(Res.error(undefined, {message: 'invalid Input'}));
case 'AdapterError':
return res.status(400).json(Res.error(undefined, {message: 'adapter Error'}));
default:
return res.serverError(error);
}