3 // JSON request/reply cache.
7 typedef struct JEntry JEntry;
14 static Cache *jsoncache;
26 jcachelookup(char *request)
29 jsoncache = newcache(sizeof(JEntry), 1000, jfree);
30 return (JEntry*)cachelookup(jsoncache, request, 1);
34 jcacheflush(char *substr)
38 cacheflush(jsoncache, substr);
45 makehttprequest(char *host, char *path, char *postdata)
50 fmtprint(&fmt, "POST %s HTTP/1.0\r\n", path);
51 fmtprint(&fmt, "Host: %s\r\n", host);
52 fmtprint(&fmt, "User-Agent: " USER_AGENT "\r\n");
53 fmtprint(&fmt, "Content-Type: application/x-www-form-urlencoded\r\n");
54 fmtprint(&fmt, "Content-Length: %d\r\n", strlen(postdata));
55 fmtprint(&fmt, "\r\n");
56 fmtprint(&fmt, "%s", postdata);
57 return fmtstrflush(&fmt);
61 makerequest(char *method, char *name1, va_list arg)
71 val = va_arg(arg, char*);
73 sysfatal("jsonrpc: nil value");
74 fmtprint(&fmt, "%U=%U&", key, val);
75 p = va_arg(arg, char*);
77 // TODO: These are SmugMug-specific, probably.
78 fmtprint(&fmt, "method=%s&", method);
80 fmtprint(&fmt, "SessionID=%s&", sessid);
81 fmtprint(&fmt, "APIKey=%s", APIKEY);
82 return fmtstrflush(&fmt);
86 dojsonhttp(Protocol *proto, char *host, char *request, int rfd, vlong rlength)
91 data = httpreq(proto, host, request, &hdr, rfd, rlength);
93 fprint(2, "httpreq: %r\n");
96 if(strcmp(hdr.contenttype, "application/json") != 0 &&
97 (strcmp(hdr.contenttype, "text/html; charset=utf-8") != 0 || data[0] != '{')){ // upload.smugmug.com, sigh
98 werrstr("bad content type: %s", hdr.contenttype);
99 fprint(2, "Content-Type: %s\n", hdr.contenttype);
100 write(2, data, hdr.contentlength);
103 if(hdr.contentlength == 0){
104 werrstr("no content");
111 jsonrpc(Protocol *proto, char *host, char *path, char *method, char *name1, va_list arg, int usecache)
113 char *httpreq, *request, *reply;
115 Json *jv, *jstat, *jmsg;
117 request = makerequest(method, name1, arg);
121 je = jcachelookup(request);
124 return jincref(je->reply);
128 rpclog("%T %s", request);
129 httpreq = makehttprequest(host, path, request);
132 if((reply = dojsonhttp(proto, host, httpreq, -1, 0)) == nil){
138 jv = parsejson(reply);
141 rpclog("%s: error parsing JSON reply: %r", method);
145 if(jstrcmp((jstat = jlookup(jv, "stat")), "ok") == 0){
147 je->reply = jincref(jv);
151 if(jstrcmp(jstat, "fail") == 0){
152 jmsg = jlookup(jv, "message");
154 // If there are no images, that's not an error!
155 // (But SmugMug says it is.)
156 if(strcmp(method, "smugmug.images.get") == 0 &&
157 jstrcmp(jmsg, "empty set - no images found") == 0){
159 jv = parsejson("{\"stat\":\"ok\", \"Images\":[]}");
161 sysfatal("parsejson: %r");
162 je->reply = jincref(jv);
166 fprint(2, "%s: %J\n", method, jv);
167 rpclog("%s: %J", method, jmsg);
172 rpclog("%s: json status: %J", method, jstat);
177 rpclog("%s: json stat=%J", method, jstat);
183 ncsmug(char *method, char *name1, ...)
188 va_start(arg, name1);
189 // TODO: Could use https only for login.
190 jv = jsonrpc(&https, HOST, PATH, method, name1, arg, 0);
192 rpclog("reply: %J", jv);
197 smug(char *method, char *name1, ...)
202 va_start(arg, name1);
203 jv = jsonrpc(&http, HOST, PATH, method, name1, arg, 1);
209 jsonupload(Protocol *proto, char *host, char *req, int rfd, vlong rlength)
211 Json *jv, *jstat, *jmsg;
214 if((reply = dojsonhttp(proto, host, req, rfd, rlength)) == nil)
217 jv = parsejson(reply);
220 fprint(2, "upload: error parsing JSON reply\n");
224 if(jstrcmp((jstat = jlookup(jv, "stat")), "ok") == 0)
227 if(jstrcmp(jstat, "fail") == 0){
228 jmsg = jlookup(jv, "message");
230 fprint(2, "upload: %J\n", jmsg);
235 fprint(2, "upload: json status: %J\n", jstat);
240 fprint(2, "upload: %J\n", jv);