2010-07-02 18 views
6

J'essaie d'envoyer un message POST avec une charge utile purement XML (je pense) en utilisant urllib2 dans IronPython. Cependant, chaque fois que je l'envoie, il renvoie le code d'erreur 400 (demande incorrecte).HTTP POST authentifié avec charge utile XML utilisant Python urllib2

J'essaie en fait de mimer un Boxee supprimer l'appel d'élément de file d'attente pour laquelle les paquets de données réels ressemble à ceci (de WireShark):

POST /action/add HTTP/1.1 
User-Agent: curl/7.16.3 (Windows build 7600; en-US; beta) boxee/0.9.21.11487 
Host: app.boxee.tv 
Accept: */* 
Accept-Encoding: deflate, gzip 
Cookie: boxee_ping_version=9; X-Mapping-oompknoc=76D730BC9E858725098BF13AEFE32EB5; boxee_app=e01e36e85d368d4112fe4d1b6587b1fd 
Connection: keep-alive 
Content-Type: text/xml 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 
Accept-Language: en-us,en;q=0.5 
Keep-Alive: 300 
Connection: keep-alive 
Content-Length: 53 

<message type="dequeue" referral="3102296"></message> 

J'utilise le code Python ci-dessous pour envoyer le POST :

def PostProtectedPage(theurl, username, password, postdata): 

    req = urllib2.Request(theurl, data=postdata) 
    req.add_header('Content-Type', 'text/xml') 
    try: 
     handle = urllib2.urlopen(req) 
    except IOError, e:     # here we are assuming we fail 
     pass 
    else:        # If we don't fail then the page isn't protected 
     print "This page isn't protected by authentication." 
     sys.exit(1) 

    if not hasattr(e, 'code') or e.code != 401:     # we got an error - but not a 401 error 
     print "This page isn't protected by authentication." 
     print 'But we failed for another reason.' 
     sys.exit(1) 

    authline = e.headers.get('www-authenticate', '')    # this gets the www-authenticat line from the headers - which has the authentication scheme and realm in it 
    if not authline: 
     print 'A 401 error without an authentication response header - very weird.' 
     sys.exit(1) 

    authobj = re.compile(r'''(?:\s*www-authenticate\s*:)?\s*(\w*)\s+realm=['"](\w+)['"]''', re.IGNORECASE)   # this regular expression is used to extract scheme and realm 
    matchobj = authobj.match(authline) 
    if not matchobj:          # if the authline isn't matched by the regular expression then something is wrong 
     print 'The authentication line is badly formed.' 
     sys.exit(1) 
    scheme = matchobj.group(1) 
    realm = matchobj.group(2) 
    if scheme.lower() != 'basic': 
     print 'This example only works with BASIC authentication.' 
     sys.exit(1) 

    base64string = base64.encodestring('%s:%s' % (username, password))[:-1] 
    authheader = "Basic %s" % base64string 
    req.add_header("Authorization", authheader) 
    try: 
     handle = urllib2.urlopen(req) 
    except IOError, e:     # here we shouldn't fail if the username/password is right 
     print "It looks like the username or password is wrong." 
     print e 
     sys.exit(1) 
    thepage = handle.read() 
    return thepage 

Cependant, chaque fois que je lance ce, il retourne erreur 400 (Bad Request)
Je sais que l'authentification est correcte parce que je l'utilise ailleurs pour chercher la file d'attente (et je ne peux pas imaginer ce n'est pas utilisé , sinon comment ne serait-il pas w dans quel compte appliquer la modification?)

En regardant la capture réseau, pourrais-je simplement manquer l'ajout de certains en-têtes à la requête? Probablement quelque chose de simple, mais je ne connais pas assez les requêtes python ou HTTP pour savoir quoi.

Modifier: BTW, j'appelle le code comme suit (il est en fait dynamique, mais cela est l'idée de base):

PostProtectedPage("http://app.boxee.tv/action/add", "user", "pass", "<message type=\"dequeue\" referral=\"3102296\"></message>") 
+1

Un conseil. Essayez de le faire en utilisant curl sur la ligne de commande en premier. Vous pouvez capturer cela en utilisant les options de débogage de curl et cela pourrait vous donner quelques indices. Il est également possible que, en python, vous deviez forger l'en-tête User-Agent curl car certaines interfaces HTTP programmatiques rejettent les agents utilisateurs inconnus, malheureusement. Une autre possibilité est que vous deviez imiter la façon dont boxee fournit des cookies au serveur. –

+0

Hmmm, bons points. J'ai ignoré l'agent utilisateur et les cookies car le processus de get a bien fonctionné sans cela. Je vais essayer. Merci. –

+0

J'ai essayé de créer un compte et de le tester moi-même, mais je ne peux pas savoir où sur boxee.tv pour déclencher cette demande normalement afin que je puisse le voir dans Wireshark. –

Répondre

0

Cela a bien fonctionné pour moi:

curl -v -A 'curl/7.16.3 (Windows build 7600; en-US; beta) boxee/0.9.21.11487' \ 
-H 'Content-Type: text/xml' -u "USER:PASS" \ 
--data '<message type="dequeue" referral="12573293"></message>' \ 
'http://app.boxee.tv/action/add' 

Mais je reçois 400 Bad Request si j'essaie de supprimer un ID de référence qui n'est pas actuellement dans la file d'attente. Si vous utilisez le même ID de référence que celui que vous avez détecté dans Wireshark, c'est très probablement ce qui se passe pour vous aussi. Utilisez

wget -nv -m -nd --user=USER --password=PASS http://app.boxee.tv/api/get_queue 

pour vous assurer que ce que vous essayez de supprimer se trouve réellement dans la file d'attente.