Switch branches/tags
Find file
Fetching contributors…
Cannot retrieve contributors at this time
124 lines (112 sloc) 6.76 KB
import httplib
import subprocess
import os
import sys
class CurlError(Exception):
"""An error occurred during an invocation of curl."""
# Up to date as of 12:01 14-Nov-2012 GMT.
messages = {
1: 'Unsupported protocol. This build of curl has no support for this protocol.',
2: 'Failed to initialize.',
3: 'URL malformed. The syntax was not correct.',
4: 'A feature or option that was needed to perform the desired request was not enabled or was explicitly disabled at build-time. To make curl able to do this, you probably need another build of libcurl!',
5: "Couldn't resolve proxy. The given proxy host could not be resolved.",
6: "Couldn't resolve host. The given remote host was not resolved.",
7: 'Failed to connect to host.',
8: "FTP weird server reply. The server sent data curl couldn't parse.",
9: "FTP access denied. The server denied login or denied access to the particular resource or directory you wanted to reach. Most often you tried to change to a directory that doesn't exist on the server.",
11: "FTP weird PASS reply. Curl couldn't parse the reply sent to the PASS request.",
13: "FTP weird PASV reply, Curl couldn't parse the reply sent to the PASV request.",
14: "FTP weird 227 format. Curl couldn't parse the 227-line the server sent.",
15: "FTP can't get host. Couldn't resolve the host IP we got in the 227-line.",
17: "FTP couldn't set binary. Couldn't change transfer method to binary.",
18: 'Partial file. Only a part of the file was transferred.',
19: "FTP couldn't download/access the given file, the RETR (or similar) command failed.",
21: 'FTP quote error. A quote command returned error from the server.',
22: 'HTTP page not retrieved. The requested url was not found or returned another error with the HTTP error code being 400 or above. This return code only appears if -f, --fail is used.',
23: "Write error. Curl couldn't write data to a local filesystem or similar.",
25: "FTP couldn't STOR file. The server denied the STOR operation, used for FTP uploading.",
26: 'Read error. Various reading problems.',
27: 'Out of memory. A memory allocation request failed.',
28: 'Operation timeout. The specified time-out period was reached according to the conditions.',
30: 'FTP PORT failed. The PORT command failed. Not all FTP servers support the PORT command, try doing a transfer using PASV instead!',
31: "FTP couldn't use REST. The REST command failed. This command is used for resumed FTP transfers.",
33: 'HTTP range error. The range "command" didn\'t work.',
34: 'HTTP post error. Internal post-request generation error.',
35: 'SSL connect error. The SSL handshaking failed.',
36: "FTP bad download resume. Couldn't continue an earlier aborted download.",
37: "FILE couldn't read file. Failed to open the file. Permissions?",
38: 'LDAP cannot bind. LDAP bind operation failed.',
39: 'LDAP search failed.',
41: 'Function not found. A required LDAP function was not found.',
42: 'Aborted by callback. An application told curl to abort the operation.',
43: 'Internal error. A function was called with a bad parameter.',
45: 'Interface error. A specified outgoing interface could not be used.',
47: 'Too many redirects. When following redirects, curl hit the maximum amount.',
48: 'Unknown option specified to libcurl. This indicates that you passed a weird option to curl that was passed on to libcurl and rejected. Read up in the manual!',
49: 'Malformed telnet option.',
51: "The peer's SSL certificate or SSH MD5 fingerprint was not OK.",
52: "The server didn't reply anything, which here is considered an error.",
53: 'SSL crypto engine not found.',
54: 'Cannot set SSL crypto engine as default.',
55: 'Failed sending network data.',
56: 'Failure in receiving network data.',
58: 'Problem with the local certificate.',
59: "Couldn't use specified SSL cipher.",
60: 'Peer certificate cannot be authenticated with known CA certificates.',
61: 'Unrecognized transfer encoding.',
62: 'Invalid LDAP URL.',
63: 'Maximum file size exceeded.',
64: 'Requested FTP SSL level failed.',
65: 'Sending the data requires a rewind that failed.',
66: 'Failed to initialise SSL Engine.',
67: 'The user name, password, or similar was not accepted and curl failed to log in.',
68: 'File not found on TFTP server.',
69: 'Permission problem on TFTP server.',
70: 'Out of disk space on TFTP server.',
71: 'Illegal TFTP operation.',
72: 'Unknown TFTP transfer ID.',
73: 'File already exists (TFTP).',
74: 'No such user (TFTP).',
75: 'Character conversion failed.',
76: 'Character conversion functions required.',
77: 'Problem with reading the SSL CA cert (path? access rights?).',
78: 'The resource referenced in the URL does not exist.',
79: 'An unspecified error occurred during the SSH session.',
80: 'Failed to shut down the SSL connection.',
82: 'Could not load CRL file, missing or wrong format (added in 7.19.0).',
83: 'Issuer check failed (added in 7.19.0).',
84: 'The FTP PRET command failed',
85: 'RTSP: mismatch of CSeq numbers',
86: 'RTSP: mismatch of Session Identifiers',
87: 'unable to parse FTP file list',
88: 'FTP chunk callback reported error'}
def __init__(self, returncode):
super(CurlError, self).__init__()
self.errno = returncode
self.message = self.messages[self.errno]
def __repr__(self):
return 'CurlError(%d)' % (self.errno,)
def __str__(self):
return self.message
def curl(*args):
"""Execute curl, returning an `httplib.HTTPResponse`."""
command = 'curl -sNi'.split() + list(args)
pipe = subprocess.Popen(command, stdin=None, stdout=subprocess.PIPE,
class mock_socket(object):
def makefile(self, *args, **kwargs):
return os.fdopen(os.dup(pipe.stdout.fileno()), *args, **kwargs)
response = httplib.HTTPResponse(mock_socket())
retcode = pipe.poll()
if retcode not in (None, 0):
raise CurlError(retcode)
# There's a problem wherein curl doesn't print the chunk length prefixes,
# instead transparently turning the chunks into a continuous stream.
# httplib.HTTPResponse, however, is expecting them. So we set `chunked` to
# False so it doesn't raise errors when reading the stream.
response.chunked = False
return response