Alex R
Alex R

Reputation: 11881

How to remove dependency on "HTTP For Humans" Requests library and use urllib instead?

I need to use the urllib for this, not urllib2, urllib3, or Requests.

The curl equivalent...

curl -H "Content-Type: application/json" -X POST -d '{"title":"My New Title","content":"blahblah","excerpt":"blah"}' http://localhost/wp-json/wp/v2/posts --user 'user:xxx'

... and the following code work fine:

r = requests.post(url + '/wp-json/wp/v2/posts', 
                  auth=HTTPBasicAuth(username, password), 
                  data=json.dumps(params), 
                  headers={'content-type': 'application/json'})

if(not(r.ok)):
    raise Exception('failed with rc=' + r.status_code)

return json.loads(r.text)

But this fails:

params = {
    'title': 'The Title',
    'content': content,
    'exerpt': 'blah'
}
postparam = json.dumps(params).encode('utf-8')

password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, url, username, password)
handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
opener = urllib.request.build_opener(handler)

req = urllib.request.Request(url + '/wp-json/wp/v2/posts', method='POST', data=postparam)
req.add_header('Content-Type', 'application/json')

r = opener.open(req)

if(r.getcode() != 200):
    raise Exception('failed with rc=' + r.getcode())

Traceback:

Traceback (most recent call last):
  File "test_wp_api.py", line 10, in <module>
    rs = create(endpoint, "test")
  File "C:\...\wordpress.py", line 28, in create
    r = opener.open(req)
  File "c:\usr\Python37-32\lib\urllib\request.py", line 531, in open
    response = meth(req, response)
  File "c:\usr\Python37-32\lib\urllib\request.py", line 641, in http_response
    'http', request, response, code, msg, hdrs)
  File "c:\usr\Python37-32\lib\urllib\request.py", line 569, in error
    return self._call_chain(*args)
  File "c:\usr\Python37-32\lib\urllib\request.py", line 503, in _call_chain
    result = func(*args)
  File "c:\usr\Python37-32\lib\urllib\request.py", line 649, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 401: Unauthorized

What's the cause, and how to fix it?

Upvotes: 2

Views: 50

Answers (1)

Ondrej K.
Ondrej K.

Reputation: 9664

I will venture a guess. Please, try this out and if it does not address your issue, I can ditch the answer (but it won't easily fit into a comment as is).

Not sure about requests. but curl when provided with credentials does not wait for challenge (HTTP 401 and info on supported authentication methods) to try (respond with) authentication (attempt). Some servers do not send such challenge and just expect pre-authenticated session or a force (lucky guess a bit) authentication. I have to talk to some hosts like that too. If that is the case, you cannot change server setup and you are OK to just assume HTTP basic is supported, you can try forcing your credentials into each request. Reusing your opener,username, and password and you also need to import base64 for this snippet which does just that:

credentials = '{}:{}'.format(username, password).encode('ascii')
credentials = base64.b64encode(credentials)
credentials = b"Basic " + credentials
opener.addheaders.append(("Authorization", credentials))

Upvotes: 2

Related Questions