400 error about missing colon in HTTP headers since API authentication change

Occasional Participant

400 error about missing colon in HTTP headers since API authentication change

We switched our code to basic auth as soon as we received a notification that digest auth was being discontinued. Unfortunately, since no method for testing the correctness of the new system was made available, we weren't able to confirm that it was correct. When the switch occurred on Friday, our ability to programmatically add new subscribers ceased working.


Attempts to use it now return the following:


<html><head>

<title>400 Bad Request</title>

</head><body>

<h1>Bad Request</h1>

<p>Your browser sent a request that this server could not understand.<br />

Request header field is missing ':' separator.<br />

<pre>

ZQ==</pre>

</p>

<hr />

<address>IBM_HTTP_Server Server at p2-ws575 Port 80</address>

</body></html>



This is a very strange error to be getting, as it implies a malformed HTTP request rather than a problem with the authentication mechanism. But the

HTTP request being made is exactly the same one that was working on Thursday. This makes me think that there is a problem with the API server.



The following is the python code that I am using to POST to the API:



xml = """<entry xmlns="http://www.w3.org/2005/Atom">

<title type="text"> </title>

<updated>2008-07-23T14:21:06.407Z</updated>

<author></author>

<id>data:,none</id>

<summary type="text">Contact</summary>

<content type="application/vnd.ctct+xml">

<Contact xmlns="http://ws.constantcontact.com/ns/1.0/">

<EmailAddress>%s</EmailAddress>

<OptInSource>ACTION_BY_CONTACT</OptInSource>

<ContactLists>

<ContactList id="

http://api.constantcontact.com/ws/customers/MYACCOUNT/lists/2" />

</ContactLists>

</Contact>

</content>

</entry>""" % recipient.email

user = '%s%%%s' % (CONSTANTCONTACT_API_KEY, CONSTANTCONTACT_LOGIN)

http = httplib2.Http()

http.add_credentials(user, CONSTANTCONTACT_PASSWORD)

response, content = http.request('

https://api.constantcontact.com/ws/customers/MYACCOUNT/contacts', 'POST',

body=xml, headers={'content-type': 'application/atom+xml'})



This code is known to have worked under your previous server configuration (it has been running in production ever since the switch to basic auth was announced).  To my knowledge there's no sample python code to compare it to, but it's a pretty simple use of httplib2.  I'm at a loss as to what the problem could be.

4 REPLIES 4
Moderator

HTTPS requests must be made over port 443.  Since it appears you are trying to connect to port 80, you may need to configure your http_request to send over port 443.  I would recommend looking at the http_request documentation for the port changing options.

Dave Berard
Senior Product Manager, Constant Contact
Occasional Participant

Note the https in the URL.  I've also tried explicitly setting the port in the URL (":443").  The error is the same.  I can only assume that the service is redirecting to a port 80 service after successful authentication.


This looks to me very much like this bug:


http://code.google.com/p/httplib2/issues/detail?id=17


However, upgrading my copy of httplib2 has not resolved the issue.  And I'm not able to replicate the issue with curl to look for redirects (auth seems to invariably fail -- is there a restriction on user agents?).


I'll try reimplementing with urllib2, but this still looks like a server-side problem to me.

Occasional Participant

Here's another python attempt, this time using the relatively archaic urllib2 (on the off chance that that httplib2 patch from 2008 wasn't committed).  I've taken this pretty much verbatim from http://www.voidspace.org.uk/python/articles/authentication.shtml , but it's consistently returning a 401.


A working python example would be really useful.  I feel confident that one of the snippets I've posted can fill this void, but I think I still need a little help from you guys.


 


    xml = """<entry xmlns="http://www.w3.org/2005/Atom">

      <title type="text"> </title>

      <updated>2008-07-23T14:21:06.407Z</updated>

      <author></author>

      <id>data:,none</id>

      <summary type="text">Contact</summary>

      <content type="application/vnd.ctct+xml">

        <Contact xmlns="http://ws.constantcontact.com/ns/1.0/">

          <EmailAddress>%s</EmailAddress>

          <OptInSource>ACTION_BY_CONTACT</OptInSource>

          <ContactLists>

            <ContactList id="http://api.constantcontact.com/ws/customers/MY_ACCOUNT/lists/2" />

          </ContactLists>

        </Contact>

      </content>

    </entry>""" % recipient.email

   

    user = '%s%%%s' % (CONSTANTCONTACT_API_KEY, CONSTANTCONTACT_LOGIN)

   

    import urllib2

    url = "https://api.constantcontact.com/ws/customers/MY_ACCOUNT/contacts"

   

    passman = urllib2.HTTPPasswordMgrWithDefaultRealm()

    passman.add_password(None, url, user, CONSTANTCONTACT_PASSWORD)

    auth = urllib2.HTTPBasicAuthHandler(passman)

    opener = urllib2.build_opener(auth)

    urllib2.install_opener(opener)



    req = urllib2.Request(url)

    req.add_header('Content-Type', 'application/atom+xml')

    resp = urllib2.urlopen(req, data=xml)

Developer Portal

View API documentation, code samples, get your API key.

Visit Page