Problem with HTTP headers in URL class


#1

First of all, this problem report pertains to the JUCE tip, retrieved with git today. It is general for all platforms but the effect is not as bad on windows as it is on MAC. I have not tested on other platforms.

I am writing a program that has some client-functionality towards a WCF service on a Windows Webserver (IIS7). For such a client request to be "approved" by IIS, it must have "Content-Type: text/xml; charset=utf8" in its headers. Juce gives the opportunity to explictly define header fields - the problem is that Juce sets Content-Type (to application/x-www-form-urlencoded), even if the user code has provided a Content-Type. In the windows case, on the wire this results in a valid header (I think the lower windows layers take the last of the Content-Type's which happens to be the user-provided one), but on MAC, the lower layers choose to COMBINE the two values, which IIS (and probably many other servers) doesn't accept (from actual packet: Content-Type: application/x-www-form-urlencoded,text/xml; charset=utf-8)

I have temporarily fixed it by letting Juce (in juce_URL.cpp, URLHelpers::createHeadersAndPostData) check if the user has provided a content-type header, before applying one. For this to work, URL::createInputStream must initialize "headers" to the value of the user-provided headers, instead of as now, add the user-provided headers after the ones created by URLHelpers::createHeadersAndPostData. 

I hope you will consider changing this in Juce. I can of course provide my working code if you like.

And last but not least, thank you for an excellent framework!

Anders

 


#2

I had the exact same problem and I also had to hack up the URL class to get it to take a caller defined content type.  It would be assume if this were fixed in Juce so that we don't have to keep patching this class after updating to head.


#3

Sorry guys, I'm struggling a bit to know exactly what you're asking for here (http protocols are not one of my main areas of expertise!).. If someone could let me know what you hacked to get it working, I'm sure I could figure out from there how to best get a fix done!


#4

Thanks for responding so fast Jules. As code is best described by ... well, code, here's a context diff of what I changed:


Index: C:/Projects/xxx/JUCE/modules/juce_core/network/juce_URL.cpp
===================================================================
--- C:/Projects/xxx/JUCE/modules/juce_core/network/juce_URL.cpp    (revision 630)
+++ C:/Projects/xxx/JUCE/modules/juce_core/network/juce_URL.cpp    (revision 631)
@@ -199,8 +199,11 @@
                  << url.getPostData();
 
             // just a short text attachment, so use simple url encoding..
-            headers << "Content-Type: application/x-www-form-urlencoded\r\nContent-length: "
-                    << (int) data.getDataSize() << "\r\n";
+            if (!headers.toLowerCase().contains("content-type"))  // only set content type if we haven't done so explicitly
+            {
+                headers << "Content-Type: application/x-www-form-urlencoded\r\n";
+            }
+            headers << "Content-length: " << (int) data.getDataSize() << "\r\n";
         }
     }
 
@@ -324,14 +327,15 @@
                                      const int timeOutMs,
                                      StringPairArray* const responseHeaders) const
 {
-    String headers;
+    String headers = extraHeaders;  // set our explicit headers first, so createHeadersAndPostData can act accordingly
     MemoryBlock headersAndPostData;
 
+    if (! headers.endsWithChar ('\n'))
+        headers << "\r\n";
+    
     if (usePostCommand)
         URLHelpers::createHeadersAndPostData (*this, headers, headersAndPostData);
-
-    headers += extraHeaders;
-
+    
     if (! headers.endsWithChar ('\n'))
         headers << "\r\n";

I basically let the user headers be added first (last half of the diff), and then only add the hardcoded content-type, if there was no content-type in the user headers (first half).

I also attach the complete juce_URL.cpp file to this post.

Anders

 

 


#5

Much obliged! I'll take a look and see what I can do with that..