FileUpload using HttpWebRequest returns (411) Length Required Error - file-upload

I have written an ActiveX control which supports drag-drop of email attachments and disk files and uploads files to a web server.
I used the samples available at this link for Uploading files
Upload files with HTTPWebrequest (multipart/form-data)
I am sending data in chunks by setting the following properties
wr = (HttpWebRequest)WebRequest.Create(UploadUrl);
wr.ContentType = "multipart/form-data; boundary=" + boundary;
wr.Method = "POST";
wr.ContentLength = contentLength;
wr.AllowWriteStreamBuffering = false;
wr.Timeout = 600000;
wr.KeepAlive = false;
wr.ReadWriteTimeout = 600000;
wr.ProtocolVersion = HttpVersion.Version10;
wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
wr.SendChunked = true;
wr.UserAgent = "Mozilla/3.0 (compatible; My Browser/1.0)";
rs = wr.GetRequestStream();
With the above settings I am getting an error (411) Length Required.
After reading the following article I realized, I dont need to set Content-Length property when I set SendChunked = true;
http://en.wikipedia.org/wiki/Chunked_transfer_encoding
But the Microsoft example code here doesn't do so
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.sendchunked.aspx
After further digging I came to know that Chunked encoding is supported in HTTP version 1.1 only. So I changed the property as follows
wr.ProtocolVersion = HttpVersion.Version11;
Now I don't see that 411 error any more.
Now, can someone with better knowledge verify my understanding here and please let me know if I am doing right.
Thanks
Ravi.

They are both just mechanisms to let the receiver know when it has reached the end of the transfer. If you want to use Content-Length, it is pretty simple. Just take your encoded byte array of POST data, and use the Length property.
ASCIIEncoding encoding = new ASCIIEncoding ();
byte[] postDataByteArray = encoding.GetBytes (postData);
wr.ContentLength = postDataByteArray.Length;

Related

Restsharp 107.x ExecuteAsync upload file to uploadsession fails (GraphAPI Sharepoint), 106.x does work

I have my below code which works proper on 106.15, I get a succesfull status. Project is Visual Studio 2022 (.Net 4.8)
accessToken = GetAccessToken()
Dim rRequest As RestRequest
Dim rClient As RestClient
Dim rResponse As RestResponse
Try
Dim data() As Byte = File.ReadAllBytes(fileSource)
rClient = New RestClient("https://graph.microsoft.com/v1.0")
rRequest = New RestRequest(uploadURL, Method.Put)
rRequest.AddHeader("Authorization", "Bearer " & accessToken)
rRequest.AddHeader("Content-Range", New ContentRangeHeaderValue(0, data.Length - 1, data.Length).ToString)
rRequest.AddHeader("Content-Length", data.Length)
rRequest.AddParameter("application/binary", data, ParameterType.RequestBody)
rResponse = Await rClient.ExecuteAsync(rRequest)
When I execute the code on 107.15 it fails with the following error : There was an error sending the request (translated from dutch)
Any idea what could be wrong or should be changed?
Looks like 108.0.1 fixes the issue, it is working now.
This commit from 03 Mar 22 shows the fix.
Please read the documentation.
Don't use this:
rRequest.AddHeader("Content-Range", New ContentRangeHeaderValue(0, data.Length - 1, data.Length).ToString)
rRequest.AddHeader("Content-Length", data.Length)
rRequest.AddParameter("application/binary", data, ParameterType.RequestBody)
use AddFile instead.
You can still add the Content-Range header manually using AddHeader. As you aren't uploading the file (although you kind of do), you might not the file name to be there. In that case, you can try this:
rRequest
.AddBody(data)
.AddHeader("Content-Range", New ContentRangeHeaderValue(0, data.Length - 1, data.Length).ToString())
When AddBody gets a byte array, it will use the application/binary content type, and set the length correctly.

C# "The request was aborted: Could not create SSL/TLS secure channel." - happening occasionally

This is a request to GoCardless test API from a Dynamics CRM plugin. I receive "The request was aborted: Could not create SSL/TLS secure channel." error. It only happens on the first request after some time without sending one. If I send it again, it will be OK. I would appreciate a lot your help.
Here is my code:
//I have tried all the following lines in comment without success
//ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate;
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
//ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
//ServicePointManager.Expect100Continue = true;
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
// Create a new WebClient instance.
string baseURL = "https://api-sandbox.gocardless.com/";
WebClient client = new WebClient();
client.Headers.Add("Content-Type", "application/json");
client.Headers.Add("Authorization", "Bearer " + t);
client.Headers.Add("GoCardless-Version", "2015-07-06");
client.Headers.Add("Accept", "application/json");
Customers model = new Customers();
customer.country_code = "GB";
model.customers = customer;
MemoryStream stream1 = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Customers));
ser.WriteObject(stream1, model);
stream1.Position = 0;
StreamReader sr = new StreamReader(stream1);
// Apply ASCII Encoding to obtain the string as a byte array.
byte[] byteArray = Encoding.ASCII.GetBytes(sr.ReadToEnd());
ReturnedCustomers result = new ReturnedCustomers();
//Upload the input string using the HTTP 1.0 POST method.
try
{
byte[] responseArray = client.UploadData(baseURL + "customers", "POST", byteArray);
string responseText = Encoding.ASCII.GetString(responseArray);
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(ReturnedCustomers));
using (Stream s = GenerateStreamFromString(responseText))
{
result = (ReturnedCustomers)serializer.ReadObject(s);
}
}
catch (WebException exception)
{
}
From the Microsoft documentation (https://msdn.microsoft.com/en-us/library/gg334752.aspx) are the following limitations:
Only the HTTP and HTTPS protocols are allowed.
Access to localhost (loopback) is not permitted.
IP addresses cannot be used. You must use a named web address that requires DNS name resolution.
Anonymous authentication is supported and recommended.
5.There is no provision for prompting the logged on user for credentials or saving those credentials.
The error may be due to seguneti things:
The certificate is invalid
The certification authority is not public
Could you check what is the value of ServicePointManager.Expect100Continue and ServicePointManager.SecurityProtocol attributes in your environment?

MultipartBody Content-Type attributes dropped on CXF Upgrade

After upgrading Apache CXF from 2.4.0 to 3.1.4, the Content-Type header on responses from JAX-RS methods have dropped several attributes.
Under CXF 2.4.0, the header is:
Content-Type: multipart/mixed; type="application/octet-stream"; boundary="uuid:61b631f1-0aa9-4cc8-ad85-3c09129ec442"; start="<DocumentName.ext>"; start-info="application/octet-stream"
Under CXF 3.1.4, it is:
Content-Type: multipart/mixed; boundary="uuid:804168d7-70ed-44e7-a471-9647372b9224"
Note: attributes type, start, start-info missing.
Here's the code we're using:
#GET
#Path( "{order_id}/document/{document_id}/file" )
#Produces("multipart/mixed")
public MultipartBody getDocument( #PathParam( "order_id") int _orderId, #PathParam( "document_id") int _documentId) throws Exception {
FileInfo fileInfo = findFileInfo( _orderId, _documentId );
List<Attachment> atts = new ArrayList<Attachment>();
File internalFile = fileInfo.getActualFile();
String fileName = fileInfo.getOriginalDocumentName();
String fileSize = String.valueOf( internalFile.length() );
ContentDisposition cd = new ContentDisposition("attachment; filename=\"" + fileName + "\"; size=" + fileSize );
InputStream inputStreamToUse = new FileInputStream( internalFile );
Attachment att = new Attachment(fileName, inputStreamToUse, cd);
atts.add( att );
return new MultipartBody(atts, true);
}
I can't find any references in the Migration Guides to changes in this area and the style of the above method seems to match the one from the getBooks2() method in the JAX-RS Multipart documentation.
Any guidance on what might be causing the different behaviour?
That was done because apparently only a multipart/related media type may have optional start and start-info attributes according to https://www.rfc-editor.org/rfc/rfc2387.
A more complete discussion of the topic is on the CXF mailing list, particularly this message which indicates that Content-Type was broken as well.

How do I set http headers in Adobe Illustrator ExtendScript when using the BridgeTalk HttpConnection object?

I am trying to make http post requests from within Illustrator ExtendScript (via BridgeTalk) and for the most part it is working. However, the documentation on using HttpConnection is non-existent and I am trying to figure out how to set http-headers. The HttpConnection object has both a requestheaders and responseheaders property so I suspect it is possible.
By default, the post requests are being sent with the Content-Type header "text/html", and I would like to override it so that I can use either "application/x-www-form-urlencoded" or "multipart/form-data".
Here is what I have so far:
var http = function (callback) {
var bt = new BridgeTalk();
bt.target = 'bridge' ;
var s = '';
s += "if ( !ExternalObject.webaccesslib ) {\n";
s += " ExternalObject.webaccesslib = new ExternalObject('lib:webaccesslib');\n";
s += "}\n";
s += "var html = '';\n";
s += "var http = new HttpConnection('http://requestb.in/1mo0r1z1');\n";
s += "http.method = 'POST';\n";
s += "http.requestheaders = 'Content-Type, application/x-www-form-urlencoded'\n";
s += "http.request = 'abc=123&def=456';\n";
s += "var c=0,t='';for(var i in http){t+=(i+':'+http[i]+'***');c++;}t='BEFORE('+c+'):'+t;alert(t);\n"; // Debug: to see what properties and values exist on the http object
s += "http.response = html;\n";
s += "http.execute() ;\n";
s += "http.response;\n";
s += "var t='AFTER:';for(var i in http){t+=(i+':'+http[i]+'***');}alert(t);\n"; // Debug: to see what properties and values have been set after executing
bt.body = s;
bt.onResult = function (evt) {
callback(evt);
};
bt.onError = function (evt) {
callback(evt);
};
bt.send();
};
Things to note:
If I try setting the requestheaders properties like in my code above, the request fails. If I comment it out, the request succeeds. The default value for requestheaders is undefined.
Examining the http object after a successful request, shows the reponseheaders properties to be set to: "Connection, keep-alive,Content-Length, 2,Content-Type, text/html; charset=utf-8,Date, Wed, 24 Jun 2015 09:45:40 GMT,Server, gunicorn/18.0,Sponsored-By, https://www.runscope.com,Via, 1.1 vegur". Before the request executes, the responseheaders is set to undefined.
If anyone could help me set the request headers (in particular the Content-Type header), I would be eternally grateful!
Solved it!
The key for setting the content-type header is to set the http.mime property as follows:
s += "http.mime = 'application/x-www-form-urlencoded';\n";
Also for completeness, you can add your own custom headers as follows:
s += "http.requestheaders = ['My-Sample-Header', 'some-value'];\n";
(It turns out the headers is an array which takes the format [key1, value1, key2, value2, .......])

Why is the HTTP header 'content-length' not always set?

I am requesting files from an IBM HTTP server via a Websphere App Server (7FP19). For most files I get the content-length header but for some, not. I discovered that when I set the last-modified value in the request to '0' then I get the content-length for all files.
This seems a bit wierd to me. Does anyone know why this might be or is it just a coincidence?
Here is some code:
connection = (HttpURLConnection) url.openConnection();
for (String value : cookies.values()) {
connection.addRequestProperty("Cookie", value); //$NON-NLS-1$
}
connection.setDoOutput(true);
connection.setRequestProperty("User-Agent", USER_AGENT); //$NON-NLS-1$
//connection.setIfModifiedSince(localLastModified);
connection.setIfModifiedSince(0);
OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream());
wr.write(post);
wr.flush();
wr.close();
....
// set file attributes
long remoteDate = connection.getLastModified();
if(rc == 304)
data.lastModified = localLastModified;
else
data.lastModified = remoteDate;
data.retCode = connection.getResponseCode();
data.contentType = connection.getContentType();
data.contentEncoding = connection.getContentEncoding();
int expectedLength = connection.getContentLength();
if(expectedLength < 0) {
log.warn("Expected length: " + expectedLength);
}
UPDATE
this was running on Wesphere FP19. I returned to FP15 and the problem was gone. The length is always returned.
Are you just getting HTTP_NOT_MODIFIED/304 back which has no body and no C-L header? This seems to be working as expected.