Actual source code: client.c
petsc-3.7.3 2016-08-01
2: #include <petscwebclient.h>
3: #pragma clang diagnostic ignored "-Wdeprecated-declarations"
4: #pragma gcc diagnostic ignored "-Wdeprecated-declarations"
6: static BIO *bio_err = NULL;
8: #define PASSWORD "password"
10: #if defined(PETSC_USE_SSL_CERTIFICATE)
11: static int password_cb(char *buf,int num, int rwflag,void *userdata)
12: {
13: if (num < strlen(PASSWORD)+1) return(0);
14: strcpy(buf,PASSWORD);
15: return(strlen(PASSWORD));
16: }
17: #endif
19: static void sigpipe_handle(int x)
20: {
21: }
25: /*
26: PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.
28: If built with PETSC_USE_SSL_CERTIFICATE requires the user have created a self-signed certificate with
30: $ saws/CA.pl -newcert (using the passphrase of password)
31: $ cat newkey.pem newcert.pem > sslclient.pem
33: and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
34: silly but it was all I could figure out.
36: */
37: PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
38: {
39: SSL_CTX *ctx;
40: #if defined(PETSC_USE_SSL_CERTIFICATE)
41: char keyfile[PETSC_MAX_PATH_LEN];
42: PetscBool exists;
44: #endif
47: if (!bio_err){
48: SSL_library_init();
49: SSL_load_error_strings();
50: bio_err = BIO_new_fp(stderr,BIO_NOCLOSE);
51: }
53: /* Set up a SIGPIPE handler */
54: signal(SIGPIPE,sigpipe_handle);
56: ctx = SSL_CTX_new(SSLv23_method());
57: SSL_CTX_set_mode(ctx,SSL_MODE_AUTO_RETRY);
59: #if defined(PETSC_USE_SSL_CERTIFICATE)
60: /* Locate keyfile */
61: PetscStrcpy(keyfile,"sslclient.pem");
62: PetscTestFile(keyfile,'r',&exists);
63: if (!exists) {
64: PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);
65: PetscStrcat(keyfile,"/");
66: PetscStrcat(keyfile,"sslclient.pem");
67: PetscTestFile(keyfile,'r',&exists);
68: if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory");
69: }
71: /* Load our keys and certificates*/
72: if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file");
74: SSL_CTX_set_default_passwd_cb(ctx,password_cb);
75: if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file");
76: #endif
78: *octx = ctx;
79: return(0);
80: }
84: PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx)
85: {
87: SSL_CTX_free(ctx);
88: return(0);
89: }
93: PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest)
94: {
95: char *request=0;
96: char contentlength[40],contenttype[80],*path,*host;
97: size_t request_len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0;
99: PetscBool flg;
102: PetscStrallocpy(url,&host);
103: PetscStrchr(host,'/',&path);
104: if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url);
105: *path = 0;
106: PetscStrlen(host,&hostlen);
108: PetscStrchr(url,'/',&path);
109: PetscStrlen(path,&pathlen);
111: if (header) {
112: PetscStrendswith(header,"\r\n",&flg);
113: if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n");
114: }
116: PetscStrlen(type,&typelen);
117: if (ctype) {
118: PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);
119: PetscStrlen(contenttype,&contenttypelen);
120: }
121: PetscStrlen(header,&headlen);
122: PetscStrlen(body,&bodylen);
123: PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);
124: PetscStrlen(contentlength,&contentlen);
126: /* Now construct our HTTP request */
127: request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
128: PetscMalloc1(request_len,&request);
129: PetscStrcpy(request,type);
130: PetscStrcat(request," ");
131: PetscStrcat(request,path);
132: PetscStrcat(request," HTTP/1.1\r\nHost: ");
133: PetscStrcat(request,host);
134: PetscFree(host);
135: PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");
136: PetscStrcat(request,header);
137: if (ctype) {
138: PetscStrcat(request,contenttype);
139: }
140: PetscStrcat(request,contentlength);
141: PetscStrcat(request,body);
142: PetscStrlen(request,&request_len);
143: PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);
145: *outrequest = request;
146: return(0);
147: }
152: /*
153: PetscHTTPSRequest - Send a request to an HTTPS server
155: Input Parameters:
156: + type - either "POST" or "GET"
157: . url - URL of request host/path
158: . header - additional header information, may be NULL
159: . ctype - data type of body, for example application/json
160: . body - data to send to server
161: . ssl - obtained with PetscHTTPSConnect()
162: - buffsize - size of buffer
164: Output Parameter:
165: . buff - everything returned from server
166: */
167: PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize)
168: {
169: char *request;
170: int r;
171: size_t request_len,len;
173: PetscBool foundbody = PETSC_FALSE;
176: PetscHTTPBuildRequest(type,url,header,ctype,body,&request);
177: PetscStrlen(request,&request_len);
179: r = SSL_write(ssl,request,(int)request_len);
180: switch (SSL_get_error(ssl,r)){
181: case SSL_ERROR_NONE:
182: if (request_len != (size_t)r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket");
183: break;
184: default:
185: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem");
186: }
188: /* Now read the server's response, globus sends it in two chunks hence must read a second time if needed */
189: PetscMemzero(buff,buffsize);
190: len = 0;
191: foundbody = PETSC_FALSE;
192: do {
193: char *clen;
194: int cl;
195: size_t nlen;
197: r = SSL_read(ssl,buff+len,(int)buffsize);
198: len += r;
199: switch (SSL_get_error(ssl,r)){
200: case SSL_ERROR_NONE:
201: break;
202: case SSL_ERROR_ZERO_RETURN:
203: foundbody = PETSC_TRUE;
204: SSL_shutdown(ssl);
205: break;
206: case SSL_ERROR_SYSCALL:
207: foundbody = PETSC_TRUE;
208: break;
209: default:
210: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem");
211: }
213: PetscStrstr(buff,"Content-Length: ",&clen);
214: if (clen) {
215: clen += 15;
216: sscanf(clen,"%d",&cl);
217: if (!cl) foundbody = PETSC_TRUE;
218: else {
219: PetscStrstr(buff,"\r\n\r\n",&clen);
220: if (clen) {
221: PetscStrlen(clen,&nlen);
222: if (nlen-4 == (size_t) cl) foundbody = PETSC_TRUE;
223: }
224: }
225: } else {
226: /* if no content length than must leave because you don't know if you can read again */
227: foundbody = PETSC_TRUE;
228: }
229: } while (!foundbody);
230: PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);
232: SSL_free(ssl);
233: PetscFree(request);
234: return(0);
235: }
239: /*
240: PetscHTTPRequest - Send a request to an HTTP server
242: Input Parameters:
243: + type - either "POST" or "GET"
244: . url - URL of request host/path
245: . header - additional header information, may be NULL
246: . ctype - data type of body, for example application/json
247: . body - data to send to server
248: . sock - obtained with PetscOpenSocket()
249: - buffsize - size of buffer
251: Output Parameter:
252: . buff - everything returned from server
253: */
254: PetscErrorCode PetscHTTPRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],int sock,char buff[],size_t buffsize)
255: {
256: char *request;
257: size_t request_len;
261: PetscHTTPBuildRequest(type,url,header,ctype,body,&request);
262: PetscStrlen(request,&request_len);
264: PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);
265: PetscFree(request);
266: PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR);
267: buff[buffsize-1] = 0;
268: PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);
269: return(0);
270: }
274: PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl)
275: {
276: BIO *sbio;
280: /* Connect the TCP socket*/
281: PetscOpenSocket(host,port,sock);
283: /* Connect the SSL socket */
284: *ssl = SSL_new(ctx);
285: sbio = BIO_new_socket(*sock,BIO_NOCLOSE);
286: SSL_set_bio(*ssl,sbio,sbio);
287: if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error");
288: return(0);
289: }
293: /*
294: Given a JSON response containing the substring with "key" : "value" where there may or not be spaces around the : returns the value.
295: */
296: PetscErrorCode PetscPullJSONValue(const char buff[],const char key[],char value[],size_t valuelen,PetscBool *found)
297: {
299: char *v,*w;
300: char work[256];
301: size_t len;
304: PetscStrcpy(work,"\"");
305: PetscStrncat(work,key,250);
306: PetscStrcat(work,"\":");
307: PetscStrstr(buff,work,&v);
308: PetscStrlen(work,&len);
309: if (v) {
310: v += len;
311: } else {
312: work[len++-1] = 0;
313: PetscStrcat(work," :");
314: PetscStrstr(buff,work,&v);
315: if (!v) {
316: *found = PETSC_FALSE;
317: return(0);
318: }
319: v += len;
320: }
321: PetscStrchr(v,'\"',&v);
322: if (!v) {
323: *found = PETSC_FALSE;
324: return(0);
325: }
326: PetscStrchr(v+1,'\"',&w);
327: if (!w) {
328: *found = PETSC_FALSE;
329: return(0);
330: }
331: *found = PETSC_TRUE;
332: PetscStrncpy(value,v+1,PetscMin((size_t)(w-v),valuelen));
333: return(0);
334: }
336: #include <ctype.h>
340: /*
341: Pushs a "key" : "value" pair onto a string
343: Ignores lengths so can cause buffer overflow
344: */
345: PetscErrorCode PetscPushJSONValue(char buff[],const char key[],const char value[],size_t bufflen)
346: {
348: size_t len;
349: PetscBool special;
352: PetscStrcmp(value,"null",&special);
353: if (!special) {
354: PetscStrcmp(value,"true",&special);
355: }
356: if (!special) {
357: PetscStrcmp(value,"false",&special);
358: }
359: if (!special) {
360: PetscInt i;
362: PetscStrlen(value,&len);
363: special = PETSC_TRUE;
364: for (i=0; i<(int)len; i++) {
365: if (!isdigit(value[i])) {
366: special = PETSC_FALSE;
367: break;
368: }
369: }
370: }
372: PetscStrcat(buff,"\"");
373: PetscStrcat(buff,key);
374: PetscStrcat(buff,"\":");
375: if (!special) {
376: PetscStrcat(buff,"\"");
377: }
378: PetscStrcat(buff,value);
379: if (!special) {
380: PetscStrcat(buff,"\"");
381: }
382: return(0);
383: }