When I try to upload files by QHttpMultiPart, there appears a problem. I use the CommonsMultipartResolver.isMultipart() to validate the request, and it returns false.
So I capture frame by Wireshark, and I found an interesting thing: the boundaries in the frame are all different.
Here is my client code
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart zipPart;
zipPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/zip"));
zipPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\""));
QFile *file = new QFile(pakPath);
file->open(QIODevice::ReadOnly);
zipPart.setBodyDevice(file);
multiPart->append(zipPart);
QNetworkRequest *request = new QNetworkRequest(QUrl(url));
manager->put(*request, multiPart);
And the server code
CommonsMultipartResolver(request.getSession().getServletContext());
if( multipartResolver.isMultipart(request) ) { // here return false
...
I have two questions:
Q1: Is the different boundary make itself be an abnormal in CommonsMultipartResolver?
Q2: Is Different boundary normal or Qt make mistake?
I have a same problem too , my boundary supposed whitout "" ,
I find the source code about QHttpMultiPart class , I found that qt has force set "" by hand . so whatever we set , it will always with "".
qt QHttpMultiPart source code
<pre><code>QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart)
{
// copy the request, we probably need to add some headers
QNetworkRequest newRequest(request);
// add Content-Type header if not there already
if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
QByteArray contentType;
contentType.reserve(34 + multiPart->d_func()->boundary.count());
contentType += "multipart/";
switch (multiPart->d_func()->contentType) {
case QHttpMultiPart::RelatedType:
contentType += "related";
break;
case QHttpMultiPart::FormDataType:
contentType += "form-data";
break;
case QHttpMultiPart::AlternativeType:
contentType += "alternative";
break;
default:
contentType += "mixed";
break;
}
// putting the boundary into quotes, recommended in RFC 2046 section 5.1.1
contentType += "; boundary=\"" + multiPart->d_func()->boundary + '"';
newRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType));
}
// add MIME-Version header if not there already (we must include the header
// if the message conforms to RFC 2045, see section 4 of that RFC)
QByteArray mimeHeader("MIME-Version");
if (!request.hasRawHeader(mimeHeader))
newRequest.setRawHeader(mimeHeader, QByteArray("1.0"));
QIODevice *device = multiPart->d_func()->device;
if (!device->isReadable()) {
if (!device->isOpen()) {
if (!device->open(QIODevice::ReadOnly))
qWarning("could not open device for reading");
} else {
qWarning("device is not readable");
}
}
return newRequest;
}
</code></pre>
I tried to inherit QHttpMultiPart and rewrite the QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart) function , but it seems too bother to do.
finally , I found a simple way to solve that , it just need to reset boundary paramter agian , that before you post data. it worked. here is my code
<pre><code>
void PeddingBizUI::ossUploadPicture_post(PolicyInfo policy, QString pathName)
{
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart keyPart;
QString fileName = getFileNameFromPath(pathName);
keyPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-
data; name=\"key\""));
QByteArray ba = QByteArray(QString(policy.dir +
fileName).toStdString().data());
qDebug()<<ba;
keyPart.setBody(ba);
QHttpPart policyPart;
policyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"policy\""));
policyPart.setBody(policy.policy.toStdString().data());
QHttpPart SignaturePart;
SignaturePart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"Signature\""));
SignaturePart.setBody(policy.signature.toStdString().data());
QHttpPart OSSAccessKeyIdPart;
OSSAccessKeyIdPart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"OSSAccessKeyId\""));
OSSAccessKeyIdPart.setBody(policy.accessId.toStdString().data());
QHttpPart success_action_statusPart;
success_action_statusPart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"success_action_status\""));
success_action_statusPart.setBody(QByteArray::number(200));
QHttpPart aclPart;
aclPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-
data; name=\"x-oss-object-acl\""));
aclPart.setBody("public-read");
QHttpPart imagePart;
QString str = QString("form-data; name=\"file\";
filename=\"%1\"").arg(fileName);
qDebug()<<fileName;
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(str));
//不可调换header的先后顺序否则导致
imagePart.setHeader(QNetworkRequest::ContentTypeHeader,
QVariant("image/jpeg")); //请求失败, 提示body data not well formed 失
败
QFile *fileOpen = new QFile(pathName);
fileOpen->open(QIODevice::ReadOnly);
imagePart.setBodyDevice(fileOpen);
fileOpen->setParent(multiPart); // we cannot delete the file now, so delete it
with the multiPart
multiPart->append(keyPart);
multiPart->append(policyPart);
multiPart->append(SignaturePart);
multiPart->append(OSSAccessKeyIdPart);
multiPart->append(success_action_statusPart);
//multiPart->append(aclPart);
multiPart->append(imagePart);
quint32 random[6];
QRandomGenerator::global()->fillRange(random);
QByteArray boundary = "--boundary_zyl_"
+ QByteArray::fromRawData(reinterpret_cast<char *>(random),
sizeof(random)).toBase64();
QUrl url(policy.host);
// QUrl url("http://arithmetic-oss.oss-cn-shenzhen.aliyuncs.com");
QNetworkRequest request(url);
QByteArray contentType;
contentType += "multipart/";
contentType += "form-data";
contentType += "; boundary=";
contentType += boundary;
multiPart->setBoundary(boundary);
request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);
QNetworkReply *reply = m_netUtils.m_manager->post(request, multiPart);
connect(reply, &QNetworkReply::finished, this, [this, multiPart](){
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
qDebug()<<"ossUploadPicture_post response";
onOssUploadPictureResponse(reply);
multiPart->setParent(reply); //内存泄露
reply->deleteLater();
});
// delete the multiPart with the reply
}</code></pre>
and then problem solved.
Related
I am getting this error when trying to upload image Process 1780056901 (Zain) terminated SIGSEGV code=1 fltno=11 ip=00000000. I am getting no help from blackberry forums, and most of blackberry documention is next to trash..and so many codes they have put are flat out wrong documentation and dont work.
void ApplicationUI::getPicture()
{
FilePicker* filePicker = new FilePicker();
filePicker->setType(FileType::Picture);
filePicker->setTitle("Select Picture");
filePicker->setMode(FilePickerMode::Picker);
filePicker->open();
QObject::connect(filePicker,
SIGNAL(fileSelected(const QStringList&)),
this,
SLOT(onFileSelected(const QStringList&)));
}
void ApplicationUI::onFileSelected(const QStringList& list) {
try
{
QFile file (list[0]);
ImageView* ay = root->findChild<ImageView*>("imageName");
if(ay != NULL)
ay->setImage(Image(list[0]));
QString body = "" ;
QSettings settings("Netvariant", "Zain");
QString locale_string = settings.value("lang").toString();
if(locale_string == "ar")
locale_string == "ar";
else
locale_string = "en";
const QUrl url("myurl");
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"imageFile\""));
imagePart.setRawHeader("Content-ID", "my#content.id"); // add any headers you like via setRawHeader()
file.open(QIODevice::ReadOnly);
imagePart.setBodyDevice(&file);
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
file.setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart
multiPart->append(imagePart);
QNetworkRequest request(url);
QNetworkAccessManager* netManager = new QNetworkAccessManager(this);
QNetworkReply *reply = netManager->post(request, multiPart);
}
catch(...)
{
}
}
This script is attempting to:
create a new folder
scan an InDesign document for all images
convert all images to grayscale in Photoshop
save new grayscale images in the new folder from Photoshop
Converting the images to grayscale in Photoshop requires the use of the BridgeTalk object, which allows for the communication between InDesign and Photoshop (the usage of the BridgeTalk object seems to be a form of Ajax).
What I have so far is almost working, being that a new folder is created, and InDesign does seem to be communicating with Photoshop via BridgeTalk. But when Photoshop is opened, nothing happens -- no new images are saved, and I'm not sure if the grayscale conversion is taking place or not...
Here is my code:
#target "InDesign"
var inDesignDocument = app.activeDocument;
var newFolder = createFolder(inDesignDocument); // if subdirectory images DNE, create this folder with the function below
sendImagesToPhotoshop(inDesignDocument, newFolder);
//---------------------------------------------------------------------------------------------------------------
function createFolder(doc)
{
try
{
/*
* type-casting the filePath property (of type object) into a String type;
* must be a String type to concatenate with the subdirectory variable (also of type String)
*/
var docPath = String(doc.filePath);
var subdirectory = "/BLACK AND WHITE IMAGES";
}
catch(e)
{
alert(e.message);
exit();
}
var imagesFolder = docPath + subdirectory; // concatenating the two variables
if(!Folder(imagesFolder).exists)
{
Folder(imagesFolder).create();
}
return imagesFolder; // for instantiation outside of this function
} // end of function createFolder
//---------------------------------------------------------------------------------------------------------------
function sendImagesToPhotoshop(doc, folder)
{
var imgs = doc.allGraphics;
var fileName = "";
var img = "";
var imgType = "";
for(var i = 0; i < imgs.length; i++)
{
if(imgs[i].itemLink != null)
{
fileName = imgs[i].itemLink.name;
img = new File(folder + "/" + fileName); // each image instantiated here
imgType = imgs[i].imageTypeName; // image type is determined here (.tif, .jpg, .png, etc..)
alert("The file \"" + fileName + "\"\n\tis a " + imgType + " file.");
// each image exported to the new folder here, by file type
switch(imgType)
{
case "GIF":
alert("This script cannot convert and export the GIF file:\n\t" + fileName + " !");
break;
case "JPG":
case "EPS":
case "PNG":
case "TIFF":
createBridgeTalkMessage(folder);
break;
default:
alert("\tUnlisted image type: " + imgType + "!\nAdd this type to the switch statement.");
break;
} // end of switch statement
} // end of if statement
} // end of for loop
} // end of function sendImagesToPhotoshop
//---------------------------------------------------------------------------------------------------------------
function createBridgeTalkMessage(imagesFolder)
{
var bt = new BridgeTalk();
bt.target = "photoshop";
bt.body = saveNewImageInPhotoshop.toSource() + "(" + imagesFolder.toSource() + ");";
bt.onError = function(e)
{
alert("Error: " + e.body);
}
bt.onResult = function(resObj){};
bt.send();
}// end of function createBridgeTalkMessage
//---------------------------------------------------------------------------------------------------------------
// called from function createBridgeTalkMessage
function saveNewImageInPhotoshop(imagePath)
{
var photoshopDoc = "";
app.displayDialogs = DialogModes.NO; // Photoshop statement, prevents status alerts from interrupting
photoshopDoc.changeMode(ChangeMode.GRAYSCALE); // convert image to GRAYSCALE
photoshopDoc.saveAs(new File(imagePath) );
photoshopDoc.close(SaveOptions.DONOTSAVECHANGES);
} // end of function saveNewImageInPhotoshop
This is based on the work of Kasyan Servetsky, found here: http://forums.adobe.com/message/3817782
Yeah I experienced issues recently with single line comments and indeed using /* ... */ did the trick. I think you can pass a string for your url but need to escape the slashes characters.
It seems you are passing a folder to Photoshop instead of an actual image file. That may probably explain your issue ;)
Loic
This is my ASP.NET for server sent events.
Response.ContentType = "text/event-stream";
Response.CacheControl = "no-cache";
//repeat loop
while (true) {
int LastEventId = Request.Headers.Get("Last-Event-ID") != null ?
Int32.Parse(Request.Headers.Get("Last-Event-ID")) : -1;
int MessageCount = UserManager.GetMessageCount(UserManager.GetUserDetails(Page.User.Identity.Name).UserId);
if (LastEventId != MessageCount)
{
Response.Write(string.Format("retry: 5000\nid: {0}\ndata: {0}\n\n", MessageCount));
Response.Flush();
}
else
{
Response.Write(string.Format("retry: 5000\nid: {0}\ndata: \n\n", MessageCount));
Response.Flush();
}
if (Response.IsClientConnected == false)
{
break;
}
Response.Close();
System.Threading.Thread.Sleep(5000);
}
Firefox browser does not reconnect after two times. The same code is working on Google Chrome. Can any one help me out with this?
Try to remove spaces after colons. Seems that Firefox parser is very sensitive to spaces and newlines. Try to change your code like this:
Response.Write(string.Format("retry:5000\nid:{0}\ndata:{0}\n\n", MessageCount));
Also defining a charset may help in some browsers:
Response.ContentType = "text/event-stream;charset=UTF-8";
Hope this helps.
I'm sending the contents of this Flex form (Don't ask why) over to node. There is a post paramteter called "photo" which is a base64 encoded image.
Contents of photo get sent over ok. Problem is when I am trying to decode the content and write them to a file.
var fs = require("fs");
fs.writeFile("arghhhh.jpg", new Buffer(request.body.photo, "base64").toString(), function(err) {});
I've tried toString("binary") as well. But it seems node doesnt decode all of the content. It seems it only decodes jpg header info and leaves the rest.
Can anyone please help me with this?
Thanks
Try removing the .toString() entirely and just write the buffer directly.
this is my full solution which would read any base64 image format, decode it and save it in the proper format in the database:
// Save base64 image to disk
try
{
// Decoding base-64 image
// Source: http://stackoverflow.com/questions/20267939/nodejs-write-base64-image-file
function decodeBase64Image(dataString)
{
var matches = dataString.match(/^data:([A-Za-z-+\/]+);base64,(.+)$/);
var response = {};
if (matches.length !== 3)
{
return new Error('Invalid input string');
}
response.type = matches[1];
response.data = new Buffer(matches[2], 'base64');
return response;
}
// Regular expression for image type:
// This regular image extracts the "jpeg" from "image/jpeg"
var imageTypeRegularExpression = /\/(.*?)$/;
// Generate random string
var crypto = require('crypto');
var seed = crypto.randomBytes(20);
var uniqueSHA1String = crypto
.createHash('sha1')
.update(seed)
.digest('hex');
var base64Data = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAZABkAAD/4Q3zaHR0cDovL25zLmFkb2JlLmN...';
var imageBuffer = decodeBase64Image(base64Data);
var userUploadedFeedMessagesLocation = '../img/upload/feed/';
var uniqueRandomImageName = 'image-' + uniqueSHA1String;
// This variable is actually an array which has 5 values,
// The [1] value is the real image extension
var imageTypeDetected = imageBuffer
.type
.match(imageTypeRegularExpression);
var userUploadedImagePath = userUploadedFeedMessagesLocation +
uniqueRandomImageName +
'.' +
imageTypeDetected[1];
// Save decoded binary image to disk
try
{
require('fs').writeFile(userUploadedImagePath, imageBuffer.data,
function()
{
console.log('DEBUG - feed:message: Saved to disk image attached by user:', userUploadedImagePath);
});
}
catch(error)
{
console.log('ERROR:', error);
}
}
catch(error)
{
console.log('ERROR:', error);
}
In nodejs 8.11.3 new Buffer(string, encoding) is deprecated, instead of this the new way to do that is Buffer.from(string, encoding) always without .toString().
For more details read the documentation in nodejs docs: Buffer
Remove .toString()
Here you decode the base64 to a buffer, which is fine, but then you convert the buffer into a string. This means that it is a string object whose code points are bytes of the buffer.
I'm currently working on a proxy server where we in this case have to modify the data (by using regexp) that we push through it.
In most cases it works fine except for websites that use gzip as content-encoding (I think), I've come across a module called compress and tried to push the chunks that I receive through a decompress / gunzip stream but it isn't really turning out as I expected. (see below for code)
figured i'd post some code to support my prob, this is the proxy that gets loaded with mvc (express):
module.exports = {
index: function(request, response){
var iframe_url = "www.nu.nl"; // site with gzip encoding
var http = require('http');
var httpClient = http.createClient(80, iframe_url);
var headers = request.headers;
headers.host = iframe_url;
var remoteRequest = httpClient.request(request.method, request.url, headers);
request.on('data', function(chunk) {
remoteRequest.write(chunk);
});
request.on('end', function() {
remoteRequest.end();
});
remoteRequest.on('response', function (remoteResponse){
var body_regexp = new RegExp("<head>"); // regex to find first head tag
var href_regexp = new RegExp('\<a href="(.*)"', 'g'); // regex to find hrefs
response.writeHead(remoteResponse.statusCode, remoteResponse.headers);
remoteResponse.on('data', function (chunk) {
var body = doDecompress(new compress.GunzipStream(), chunk);
body = body.replace(body_regexp, "<head><base href=\"http://"+ iframe_url +"/\">");
body = body.replace(href_regexp, '<a href="#" onclick="javascript:return false;"');
response.write(body, 'binary');
});
remoteResponse.on('end', function() {
response.end();
});
});
}
};
at the var body part i want to read the body and for example in this case remove all hrefs by replacing them with an #. The problem here of course is when we have an site which is gzip encoded/ compressed it's all jibberish and we can't apply the regexps.
now I've already tired to mess around with the node-compress module:
doDecompress(new compress.GunzipStream(), chunk);
which refers to
function doDecompress(decompressor, input) {
var d1 = input.substr(0, 25);
var d2 = input.substr(25);
sys.puts('Making decompression requests...');
var output = '';
decompressor.setInputEncoding('binary');
decompressor.setEncoding('utf8');
decompressor.addListener('data', function(data) {
output += data;
}).addListener('error', function(err) {
throw err;
}).addListener('end', function() {
sys.puts('Decompressed length: ' + output.length);
sys.puts('Raw data: ' + output);
});
decompressor.write(d1);
decompressor.write(d2);
decompressor.close();
sys.puts('Requests done.');
}
But it fails on it since the chunk input is an object, so i tried supplying it as an chunk.toString() which also fails with invalid input data.
I was wondering if I am at all heading in the right direction?
The decompressor expects binary encoded input. The chunk that your response receives is an instance of Buffer which toString() method does by default give you an UTF-8 encoded string back.
So you have to use chunk.toString('binary') to make it work, this can also be seen in the demo.