I have figured out how to do GET, PUTs, DELETEs and basic POST using pycurl.
Nevertheless, I can't figure out what is the equivalent of this curl command line (which works perfectly fine) to python:
curl -u admin:geoserver -XPOST -H 'Content-type: application/vnd.ogc.sld+xml'
-d @/Users/rburhum/src/calthorpe/calthorpe/server/calthorpe/media/styles/1_my-scenario
"http://127.0.0.1:8080/geoserver/rest/styles?name=1_my-scenario" -v
I have seen the samples at the repo. Nevertheless, passing one parameter (in this case name) and a file to be uploaded doesn't seem to work.
For PUT calls, I have successfully used:
filesize = path.getsize(sldFile)
f = open(sldFile,'rb')
c = pycurl.Curl()
c.setopt(pycurl.HTTPHEADER, ["Content-type: application/vnd.ogc.sld+xml"])
c.setopt(pycurl.USERPWD, GEOSERVER_USER + ':' + GEOSERVER_PASSWORD)
c.setopt(pycurl.INFILESIZE, filesize)
c.setopt(c.URL, str(GEOSERVER_URL + '/rest/styles/' + path.basename(sldFile)))
c.setopt(pycurl.PUT, 1)
c.setopt(pycurl.INFILE, f)
c.perform()
f.close()
thus, I naively thought that the POST equivalent would be:
filesize = path.getsize(sldFile)
f = open(sldFile,'rb')
c = pycurl.Curl()
c.setopt(c.URL, str(GEOSERVER_URL + '/rest/styles?name=' + path.basename(sldFile)))
c.setopt(pycurl.POST, 1)
c.setopt(pycurl.HTTPHEADER, ["Content-type: application/vnd.ogc.sld+xml"])
c.setopt(pycurl.USERPWD, GEOSERVER_USER + ':' + GEOSERVER_PASSWORD)
c.setopt(pycurl.INFILESIZE, filesize)
c.setopt(pycurl.INFILE, f)
c.perform()
f.close()
The verbose output of the curl command displays this:
(calthorpe_env)rburhum@peru.local ~/src/calthorpe/calthorpe/server/calthorpe $calthorpe/server/calthorpe POST -H 'Content-type: application/vnd.ogc.sld+xml' -d@/Users/rburhum/src/calthorpe/calthorpe/server/calthorpe/media/styles/1_my-scenario "http://127.0.0.1:8080/geoserver/rest/styles?name=1_my-scenario" -v * About to connect() to 127.0.0.1 port 8080 (#0) * Trying 127.0.0.1... connected * Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0) * Server auth using Basic with user 'admin'
POST /geoserver/rest/styles?name=1_my-scenario HTTP/1.1 Authorization: Basic YWRtaW46Z2Vvc2VydmVy User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5 Host: 127.0.0.1:8080 Accept: / Content-type: application/vnd.ogc.sld+xml Content-Length: 28135 Expect: 100-continue
> < HTTP/1.1 100 Continue < HTTP/1.1 201 Created < Date: Mon, 05 Mar 2012 07:39:43 GMT < Location: http://127.0.0.1:8080/geoserver/rest/styles/1_my-scenario < Server: Noelios-Restlet-Engine/1.0..8 < Transfer-Encoding: chunked < * Connection #0 to host 127.0.0.1 left intact * Closing connection #0
I can clearly see that the content length is correct.
In contrast, when I do a verbose output of my POST code above, I can see that the content length is -1 (and hence the file is not being passed and the server gives back a 500). I have mocked with the HTTPPOST variable, which under certain combinations makes the content length be correct, but I still cannot get the exact equivalent of the CURL command above to work.
I had to combine several examples to find the right combination, and of course, I used some help from some nice people at the IRC channel. The only way I could manage to get it to work is to do a slight variation of this pycurl sample which wasn't working as described for me.
class FileReader:
def __init__(self, fp):
self.fp = fp
def read_callback(self, size):
return self.fp.read(size)
then later, I would setup the call like this:
c = pycurl.Curl()
c.setopt(c.URL, str(GEOSERVER_URL + '/rest/styles?name=' + path.basename(sldFile)))
c.setopt(pycurl.POST, 1)
filesize = path.getsize(sldFile)
f = open(sldFile,'rb')
c.setopt(pycurl.POSTFIELDSIZE, filesize)
c.setopt(pycurl.READFUNCTION, FileReader(f).read_callback)
c.setopt(pycurl.HTTPHEADER, ["Content-type: application/vnd.ogc.sld+xml"])
c.setopt(pycurl.USERPWD, GEOSERVER_USER + ':' + GEOSERVER_PASSWORD)
c.perform()
f.close()
Notice that the original sample did not use a POSTFIELDSIZE (only had INFILESIZE), without it, I could not get it to work.
As a side note, in my case, sldFile has already been slugify'ed, so no need to urlencode, otherwise, you may want to do that.