xref: /petsc/src/sys/webclient/client.c (revision 4683183ff602abad4ed575829633a91c06c87c27)
1b967cddfSBarry Smith 
20efc6a03SBarry Smith #include <petscwebclient.h>
3bb04b57dSBarry Smith #pragma clang diagnostic ignored "-Wdeprecated-declarations"
445e40e47SBarry Smith #pragma gcc diagnostic ignored "-Wdeprecated-declarations"
5b967cddfSBarry Smith 
6b967cddfSBarry Smith static BIO *bio_err = NULL;
7b967cddfSBarry Smith 
8b967cddfSBarry Smith #define PASSWORD "password"
9b967cddfSBarry Smith 
104a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
11b967cddfSBarry Smith static int password_cb(char *buf,int num, int rwflag,void *userdata)
12b967cddfSBarry Smith {
13b967cddfSBarry Smith   if (num < strlen(PASSWORD)+1) return(0);
14b967cddfSBarry Smith   strcpy(buf,PASSWORD);
15b967cddfSBarry Smith   return(strlen(PASSWORD));
16b967cddfSBarry Smith }
17b967cddfSBarry Smith #endif
18b967cddfSBarry Smith 
19b967cddfSBarry Smith static void sigpipe_handle(int x)
20b967cddfSBarry Smith {
21b967cddfSBarry Smith }
22b967cddfSBarry Smith 
23b967cddfSBarry Smith #undef __FUNCT__
24b967cddfSBarry Smith #define __FUNCT__ "PetscSSLInitializeContext"
25*4683183fSBarry Smith /*@C
26b967cddfSBarry Smith     PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.
27b967cddfSBarry Smith 
28*4683183fSBarry Smith     Output Parameter:
29*4683183fSBarry Smith .   octx - the SSL_CTX to be passed to PetscHTTPSConnect
30b967cddfSBarry Smith 
31*4683183fSBarry Smith     Level: advanced
32*4683183fSBarry Smith 
33*4683183fSBarry Smith     If PETSc was ./configure -with-ssl-certificate requires the user have created a self-signed certificate with
3468e69593SBarry Smith $    saws/CA.pl  -newcert  (using the passphrase of password)
35b967cddfSBarry Smith $    cat newkey.pem newcert.pem > sslclient.pem
36b967cddfSBarry Smith 
37b967cddfSBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
38b967cddfSBarry Smith     silly but it was all I could figure out.
39b967cddfSBarry Smith 
40*4683183fSBarry Smith .seealso: PetscSSLDestroyContext(), PetscHTTPSConnect(), PetscHTTPSRequest()
41*4683183fSBarry Smith 
42*4683183fSBarry Smith @*/
43b967cddfSBarry Smith PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
44b967cddfSBarry Smith {
45b967cddfSBarry Smith     SSL_CTX        *ctx;
464a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
47b967cddfSBarry Smith     char           keyfile[PETSC_MAX_PATH_LEN];
48b967cddfSBarry Smith     PetscBool      exists;
49b967cddfSBarry Smith     PetscErrorCode ierr;
50b967cddfSBarry Smith #endif
51b967cddfSBarry Smith 
52b967cddfSBarry Smith     PetscFunctionBegin;
53b967cddfSBarry Smith     if (!bio_err){
54b967cddfSBarry Smith       SSL_library_init();
55b967cddfSBarry Smith       SSL_load_error_strings();
56b967cddfSBarry Smith       bio_err = BIO_new_fp(stderr,BIO_NOCLOSE);
57b967cddfSBarry Smith     }
58b967cddfSBarry Smith 
59b967cddfSBarry Smith     /* Set up a SIGPIPE handler */
60b967cddfSBarry Smith     signal(SIGPIPE,sigpipe_handle);
61b967cddfSBarry Smith 
62d8dcb26dSBarry Smith     ctx  = SSL_CTX_new(SSLv23_method());
635dc0f0a4SBarry Smith     SSL_CTX_set_mode(ctx,SSL_MODE_AUTO_RETRY);
64b967cddfSBarry Smith 
654a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
66b967cddfSBarry Smith     /* Locate keyfile */
67b967cddfSBarry Smith     ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr);
68b967cddfSBarry Smith     ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr);
69b967cddfSBarry Smith     if (!exists) {
70b967cddfSBarry Smith       ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
71b967cddfSBarry Smith       ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr);
72b967cddfSBarry Smith       ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr);
73b967cddfSBarry Smith       ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr);
74b967cddfSBarry Smith       if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory");
75b967cddfSBarry Smith     }
76b967cddfSBarry Smith 
77b967cddfSBarry Smith     /* Load our keys and certificates*/
78b967cddfSBarry Smith     if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file");
79b967cddfSBarry Smith 
80b967cddfSBarry Smith     SSL_CTX_set_default_passwd_cb(ctx,password_cb);
81b967cddfSBarry Smith     if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file");
82b967cddfSBarry Smith #endif
83b967cddfSBarry Smith 
84b967cddfSBarry Smith     *octx = ctx;
85b967cddfSBarry Smith     PetscFunctionReturn(0);
86b967cddfSBarry Smith }
87b967cddfSBarry Smith 
88b967cddfSBarry Smith #undef __FUNCT__
89b967cddfSBarry Smith #define __FUNCT__ "PetscSSLDestroyContext"
90*4683183fSBarry Smith /*@C
91*4683183fSBarry Smith      PetscSSLDestroyContext - frees a SSL_CTX obtained with PetscSSLInitializeContext()
92*4683183fSBarry Smith 
93*4683183fSBarry Smith      Input Parameter:
94*4683183fSBarry Smith .     ctx - the SSL_CTX
95*4683183fSBarry Smith 
96*4683183fSBarry Smith     Level: advanced
97*4683183fSBarry Smith 
98*4683183fSBarry Smith .seealso: PetscSSLInitializeContext(), PetscHTTPSConnect()
99*4683183fSBarry Smith @*/
100b967cddfSBarry Smith PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx)
101b967cddfSBarry Smith {
102b967cddfSBarry Smith   PetscFunctionBegin;
103b967cddfSBarry Smith   SSL_CTX_free(ctx);
104b967cddfSBarry Smith   PetscFunctionReturn(0);
105b967cddfSBarry Smith }
106b967cddfSBarry Smith 
107b967cddfSBarry Smith #undef __FUNCT__
10804102261SBarry Smith #define __FUNCT__ "PetscHTTPBuildRequest"
109*4683183fSBarry Smith static PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest)
110b967cddfSBarry Smith {
111b967cddfSBarry Smith   char           *request=0;
11293e1d32fSBarry Smith   char           contentlength[40],contenttype[80],*path,*host;
1137a3410edSBarry Smith   size_t         request_len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0;
114b967cddfSBarry Smith   PetscErrorCode ierr;
115b967cddfSBarry Smith   PetscBool      flg;
116b967cddfSBarry Smith 
117b967cddfSBarry Smith   PetscFunctionBegin;
11893e1d32fSBarry Smith   ierr = PetscStrallocpy(url,&host);CHKERRQ(ierr);
11993e1d32fSBarry Smith   ierr = PetscStrchr(host,'/',&path);CHKERRQ(ierr);
12093e1d32fSBarry Smith   if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url);
121c245270aSBarry Smith   *path = 0;
12293e1d32fSBarry Smith   ierr  = PetscStrlen(host,&hostlen);CHKERRQ(ierr);
12393e1d32fSBarry Smith 
12493e1d32fSBarry Smith   ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr);
12593e1d32fSBarry Smith   ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr);
12693e1d32fSBarry Smith 
127b967cddfSBarry Smith   if (header) {
128b967cddfSBarry Smith     ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr);
129b967cddfSBarry Smith     if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n");
130b967cddfSBarry Smith   }
131b967cddfSBarry Smith 
132b967cddfSBarry Smith   ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr);
133b967cddfSBarry Smith   if (ctype) {
134b967cddfSBarry Smith     ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr);
135b967cddfSBarry Smith     ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr);
136b967cddfSBarry Smith   }
137b967cddfSBarry Smith   ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr);
138b967cddfSBarry Smith   ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr);
139b967cddfSBarry Smith   ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr);
140b967cddfSBarry Smith   ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr);
141b967cddfSBarry Smith 
142b967cddfSBarry Smith   /* Now construct our HTTP request */
14393e1d32fSBarry Smith   request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
144fe278a28SBarry Smith   ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr);
145b967cddfSBarry Smith   ierr = PetscStrcpy(request,type);CHKERRQ(ierr);
146b967cddfSBarry Smith   ierr = PetscStrcat(request," ");CHKERRQ(ierr);
14793e1d32fSBarry Smith   ierr = PetscStrcat(request,path);CHKERRQ(ierr);
14893e1d32fSBarry Smith   ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr);
14993e1d32fSBarry Smith   ierr = PetscStrcat(request,host);CHKERRQ(ierr);
15093e1d32fSBarry Smith   ierr = PetscFree(host);CHKERRQ(ierr);
15193e1d32fSBarry Smith   ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr);
152b967cddfSBarry Smith   ierr = PetscStrcat(request,header);CHKERRQ(ierr);
153b967cddfSBarry Smith   if (ctype) {
154b967cddfSBarry Smith     ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr);
155b967cddfSBarry Smith   }
156b967cddfSBarry Smith   ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr);
157b967cddfSBarry Smith   ierr = PetscStrcat(request,body);CHKERRQ(ierr);
158b967cddfSBarry Smith   ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr);
159b967cddfSBarry Smith   ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr);
160b967cddfSBarry Smith 
16104102261SBarry Smith   *outrequest = request;
16204102261SBarry Smith   PetscFunctionReturn(0);
16304102261SBarry Smith }
16404102261SBarry Smith 
16504102261SBarry Smith 
16604102261SBarry Smith #undef __FUNCT__
16704102261SBarry Smith #define __FUNCT__ "PetscHTTPSRequest"
168*4683183fSBarry Smith /*@C
16904102261SBarry Smith      PetscHTTPSRequest - Send a request to an HTTPS server
17004102261SBarry Smith 
17104102261SBarry Smith    Input Parameters:
17204102261SBarry Smith +   type - either "POST" or "GET"
17304102261SBarry Smith .   url -  URL of request host/path
17404102261SBarry Smith .   header - additional header information, may be NULL
17504102261SBarry Smith .   ctype - data type of body, for example application/json
17604102261SBarry Smith .   body - data to send to server
17704102261SBarry Smith .   ssl - obtained with PetscHTTPSConnect()
17804102261SBarry Smith -   buffsize - size of buffer
17904102261SBarry Smith 
18004102261SBarry Smith    Output Parameter:
18104102261SBarry Smith .   buff - everything returned from server
182*4683183fSBarry Smith 
183*4683183fSBarry Smith     Level: advanced
184*4683183fSBarry Smith 
185*4683183fSBarry Smith .seealso: PetscHTTPRequest(), PetscHTTPSConnect(), PetscSSLInitializeContext(), PetscSSLDestroyContext(), PetscPullJSONValue()
186*4683183fSBarry Smith 
187*4683183fSBarry Smith @*/
18804102261SBarry Smith PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize)
18904102261SBarry Smith {
19004102261SBarry Smith   char           *request;
19104102261SBarry Smith   int            r;
19204102261SBarry Smith   size_t         request_len,len;
19304102261SBarry Smith   PetscErrorCode ierr;
1945dc0f0a4SBarry Smith   PetscBool      foundbody = PETSC_FALSE;
19504102261SBarry Smith 
19604102261SBarry Smith   PetscFunctionBegin;
19704102261SBarry Smith   ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr);
19804102261SBarry Smith   ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr);
19904102261SBarry Smith 
200d8dcb26dSBarry Smith   r = SSL_write(ssl,request,(int)request_len);
201b967cddfSBarry Smith   switch (SSL_get_error(ssl,r)){
202b967cddfSBarry Smith     case SSL_ERROR_NONE:
203d8dcb26dSBarry Smith       if (request_len != (size_t)r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket");
204b967cddfSBarry Smith       break;
205b967cddfSBarry Smith     default:
206b967cddfSBarry Smith       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem");
207b967cddfSBarry Smith   }
208b967cddfSBarry Smith 
2095dc0f0a4SBarry Smith   /* Now read the server's response, globus sends it in two chunks hence must read a second time if needed */
2105dc0f0a4SBarry Smith   ierr      = PetscMemzero(buff,buffsize);CHKERRQ(ierr);
2115dc0f0a4SBarry Smith   len       = 0;
2125dc0f0a4SBarry Smith   foundbody = PETSC_FALSE;
2135dc0f0a4SBarry Smith   do {
2145dc0f0a4SBarry Smith     char   *clen;
2155dc0f0a4SBarry Smith     int    cl;
2165dc0f0a4SBarry Smith     size_t nlen;
2175dc0f0a4SBarry Smith 
2185dc0f0a4SBarry Smith     r = SSL_read(ssl,buff+len,(int)buffsize);
2195dc0f0a4SBarry Smith     len += r;
220b967cddfSBarry Smith     switch (SSL_get_error(ssl,r)){
221b967cddfSBarry Smith     case SSL_ERROR_NONE:
222b967cddfSBarry Smith       break;
223b967cddfSBarry Smith     case SSL_ERROR_ZERO_RETURN:
2245dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2255dc0f0a4SBarry Smith       SSL_shutdown(ssl);
226b967cddfSBarry Smith       break;
227b967cddfSBarry Smith     case SSL_ERROR_SYSCALL:
2285dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
229b967cddfSBarry Smith       break;
230b967cddfSBarry Smith     default:
231b967cddfSBarry Smith       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem");
232b967cddfSBarry Smith     }
2335dc0f0a4SBarry Smith 
2345dc0f0a4SBarry Smith     ierr = PetscStrstr(buff,"Content-Length: ",&clen);CHKERRQ(ierr);
2355dc0f0a4SBarry Smith     if (clen) {
2365dc0f0a4SBarry Smith       clen += 15;
2375dc0f0a4SBarry Smith       sscanf(clen,"%d",&cl);
2385dc0f0a4SBarry Smith       if (!cl) foundbody = PETSC_TRUE;
2395dc0f0a4SBarry Smith       else {
2405dc0f0a4SBarry Smith         ierr = PetscStrstr(buff,"\r\n\r\n",&clen);CHKERRQ(ierr);
2415dc0f0a4SBarry Smith         if (clen) {
2425dc0f0a4SBarry Smith           ierr = PetscStrlen(clen,&nlen);CHKERRQ(ierr);
2435dc0f0a4SBarry Smith           if (nlen-4 == (size_t) cl) foundbody = PETSC_TRUE;
2445dc0f0a4SBarry Smith         }
2455dc0f0a4SBarry Smith       }
2465dc0f0a4SBarry Smith     } else {
2475dc0f0a4SBarry Smith       /* if no content length than must leave because you don't know if you can read again */
2485dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2495dc0f0a4SBarry Smith     }
2505dc0f0a4SBarry Smith   } while (!foundbody);
251b967cddfSBarry Smith   ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr);
252b967cddfSBarry Smith 
253b967cddfSBarry Smith   SSL_free(ssl);
254b967cddfSBarry Smith   ierr = PetscFree(request);CHKERRQ(ierr);
255b967cddfSBarry Smith   PetscFunctionReturn(0);
256b967cddfSBarry Smith }
257b967cddfSBarry Smith 
258b967cddfSBarry Smith #undef __FUNCT__
25904102261SBarry Smith #define __FUNCT__ "PetscHTTPRequest"
260*4683183fSBarry Smith /*@C
26104102261SBarry Smith      PetscHTTPRequest - Send a request to an HTTP server
26204102261SBarry Smith 
26304102261SBarry Smith    Input Parameters:
26404102261SBarry Smith +   type - either "POST" or "GET"
26504102261SBarry Smith .   url -  URL of request host/path
26604102261SBarry Smith .   header - additional header information, may be NULL
26704102261SBarry Smith .   ctype - data type of body, for example application/json
26804102261SBarry Smith .   body - data to send to server
26904102261SBarry Smith .   sock - obtained with PetscOpenSocket()
27004102261SBarry Smith -   buffsize - size of buffer
27104102261SBarry Smith 
27204102261SBarry Smith    Output Parameter:
27304102261SBarry Smith .   buff - everything returned from server
274*4683183fSBarry Smith 
275*4683183fSBarry Smith     Level: advanced
276*4683183fSBarry Smith 
277*4683183fSBarry Smith .seealso: PetscHTTPSRequest(), PetscOpenSocket(), PetscHTTPSConnect(), PetscPullJSONValue()
278*4683183fSBarry Smith @*/
27904102261SBarry Smith PetscErrorCode PetscHTTPRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],int sock,char buff[],size_t buffsize)
28004102261SBarry Smith {
28104102261SBarry Smith   char           *request;
28204102261SBarry Smith   size_t         request_len;
28304102261SBarry Smith   PetscErrorCode ierr;
28404102261SBarry Smith 
28504102261SBarry Smith   PetscFunctionBegin;
28604102261SBarry Smith   ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr);
28704102261SBarry Smith   ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr);
28804102261SBarry Smith 
28904102261SBarry Smith   ierr = PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
29004102261SBarry Smith   ierr = PetscFree(request);CHKERRQ(ierr);
29104102261SBarry Smith   PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR);
29204102261SBarry Smith   buff[buffsize-1] = 0;
29304102261SBarry Smith   ierr = PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);CHKERRQ(ierr);
29404102261SBarry Smith   PetscFunctionReturn(0);
29504102261SBarry Smith }
29604102261SBarry Smith 
29704102261SBarry Smith #undef __FUNCT__
298b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSConnect"
299*4683183fSBarry Smith /*@C
300*4683183fSBarry Smith       PetscHTTPSConnect - connect to a HTTPS server
301*4683183fSBarry Smith 
302*4683183fSBarry Smith     Input Parameters:
303*4683183fSBarry Smith +    host - the name of the machine hosting the HTTPS server
304*4683183fSBarry Smith .    port - the port number where the server is hosting, usually 443
305*4683183fSBarry Smith -    ctx - value obtained with PetscSSLInitializeContext()
306*4683183fSBarry Smith 
307*4683183fSBarry Smith     Output Parameters:
308*4683183fSBarry Smith +    sock - socket to connect
309*4683183fSBarry Smith -    ssl - the argument passed to PetscHTTPSRequest()
310*4683183fSBarry Smith 
311*4683183fSBarry Smith     Level: advanced
312*4683183fSBarry Smith 
313*4683183fSBarry Smith .seealso: PetscOpenSocket(), PetscHTTPSRequest(), PetscSSLInitializeContext()
314*4683183fSBarry Smith @*/
315b967cddfSBarry Smith PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl)
316b967cddfSBarry Smith {
317b967cddfSBarry Smith   BIO            *sbio;
318b967cddfSBarry Smith   PetscErrorCode ierr;
319b967cddfSBarry Smith 
320b967cddfSBarry Smith   PetscFunctionBegin;
321b967cddfSBarry Smith   /* Connect the TCP socket*/
322b967cddfSBarry Smith   ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr);
323b967cddfSBarry Smith 
324b967cddfSBarry Smith   /* Connect the SSL socket */
325b967cddfSBarry Smith   *ssl = SSL_new(ctx);
326b967cddfSBarry Smith   sbio = BIO_new_socket(*sock,BIO_NOCLOSE);
327b967cddfSBarry Smith   SSL_set_bio(*ssl,sbio,sbio);
328b967cddfSBarry Smith   if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error");
329b967cddfSBarry Smith   PetscFunctionReturn(0);
330b967cddfSBarry Smith }
331b967cddfSBarry Smith 
33268e69593SBarry Smith #undef __FUNCT__
33368e69593SBarry Smith #define __FUNCT__ "PetscPullJSONValue"
334*4683183fSBarry Smith /*@C
335*4683183fSBarry Smith      PetscPullJSONValue - Given a JSON response containing the substring with "key" : "value"  where there may or not be spaces around the : returns the value.
336*4683183fSBarry Smith 
337*4683183fSBarry Smith     Input Parameters:
338*4683183fSBarry Smith +    buff - the char array containing the possible values
339*4683183fSBarry Smith .    key - the key of the requested value
340*4683183fSBarry Smith -    valuelen - the length of the array to contain the value associated with the key
341*4683183fSBarry Smith 
342*4683183fSBarry Smith     Output Parameters:
343*4683183fSBarry Smith +    value - the value obtained
344*4683183fSBarry Smith -    found - flag indicating if the value was found in the buff
345*4683183fSBarry Smith 
346*4683183fSBarry Smith     Level: advanced
347*4683183fSBarry Smith 
348*4683183fSBarry Smith @*/
34968e69593SBarry Smith PetscErrorCode PetscPullJSONValue(const char buff[],const char key[],char value[],size_t valuelen,PetscBool *found)
35068e69593SBarry Smith {
35168e69593SBarry Smith   PetscErrorCode ierr;
35268e69593SBarry Smith   char           *v,*w;
35368e69593SBarry Smith   char           work[256];
35468e69593SBarry Smith   size_t         len;
35568e69593SBarry Smith 
35668e69593SBarry Smith   PetscFunctionBegin;
35768e69593SBarry Smith   ierr = PetscStrcpy(work,"\"");CHKERRQ(ierr);
35868e69593SBarry Smith   ierr = PetscStrncat(work,key,250);CHKERRQ(ierr);
35968e69593SBarry Smith   ierr = PetscStrcat(work,"\":");CHKERRQ(ierr);
36068e69593SBarry Smith   ierr = PetscStrstr(buff,work,&v);CHKERRQ(ierr);
36168e69593SBarry Smith   ierr = PetscStrlen(work,&len);CHKERRQ(ierr);
36268e69593SBarry Smith   if (v) {
36368e69593SBarry Smith     v += len;
36468e69593SBarry Smith   } else {
36568e69593SBarry Smith     work[len++-1] = 0;
36668e69593SBarry Smith     ierr = PetscStrcat(work," :");CHKERRQ(ierr);
36768e69593SBarry Smith     ierr = PetscStrstr(buff,work,&v);CHKERRQ(ierr);
36868e69593SBarry Smith     if (!v) {
36968e69593SBarry Smith       *found = PETSC_FALSE;
37068e69593SBarry Smith       PetscFunctionReturn(0);
37168e69593SBarry Smith     }
37268e69593SBarry Smith     v += len;
37368e69593SBarry Smith   }
37468e69593SBarry Smith   ierr = PetscStrchr(v,'\"',&v);CHKERRQ(ierr);
37568e69593SBarry Smith   if (!v) {
37668e69593SBarry Smith     *found = PETSC_FALSE;
37768e69593SBarry Smith     PetscFunctionReturn(0);
37868e69593SBarry Smith   }
37968e69593SBarry Smith   ierr = PetscStrchr(v+1,'\"',&w);CHKERRQ(ierr);
38068e69593SBarry Smith   if (!w) {
38168e69593SBarry Smith     *found = PETSC_FALSE;
38268e69593SBarry Smith     PetscFunctionReturn(0);
38368e69593SBarry Smith   }
38468e69593SBarry Smith   *found = PETSC_TRUE;
385c1f4622dSBarry Smith   ierr = PetscStrncpy(value,v+1,PetscMin((size_t)(w-v),valuelen));CHKERRQ(ierr);
38668e69593SBarry Smith   PetscFunctionReturn(0);
38768e69593SBarry Smith }
3885dc0f0a4SBarry Smith 
3895dc0f0a4SBarry Smith #include <ctype.h>
3905dc0f0a4SBarry Smith 
3915dc0f0a4SBarry Smith #undef __FUNCT__
3925dc0f0a4SBarry Smith #define __FUNCT__ "PetscPushJSONValue"
393*4683183fSBarry Smith /*@C
394*4683183fSBarry Smith     PetscPushJSONValue -  Puts a "key" : "value" pair onto a string
3955dc0f0a4SBarry Smith 
396*4683183fSBarry Smith     Input Parameters:
397*4683183fSBarry Smith +   buffer - the char array where the value will be put
398*4683183fSBarry Smith .   key - the key value to be set
399*4683183fSBarry Smith .   value - the value associated with the key
400*4683183fSBarry Smith -   bufflen - the size of the buffer (currently ignored)
401*4683183fSBarry Smith 
402*4683183fSBarry Smith     Level: advanced
403*4683183fSBarry Smith 
404*4683183fSBarry Smith     Notes: Ignores lengths so can cause buffer overflow
405*4683183fSBarry Smith @*/
4065dc0f0a4SBarry Smith PetscErrorCode PetscPushJSONValue(char buff[],const char key[],const char value[],size_t bufflen)
4075dc0f0a4SBarry Smith {
4085dc0f0a4SBarry Smith   PetscErrorCode ierr;
4095dc0f0a4SBarry Smith   size_t         len;
4105dc0f0a4SBarry Smith   PetscBool      special;
4115dc0f0a4SBarry Smith 
4125dc0f0a4SBarry Smith   PetscFunctionBegin;
4135dc0f0a4SBarry Smith   ierr = PetscStrcmp(value,"null",&special);CHKERRQ(ierr);
4145dc0f0a4SBarry Smith   if (!special) {
4155dc0f0a4SBarry Smith     ierr = PetscStrcmp(value,"true",&special);CHKERRQ(ierr);
4165dc0f0a4SBarry Smith   }
4175dc0f0a4SBarry Smith   if (!special) {
4185dc0f0a4SBarry Smith     ierr = PetscStrcmp(value,"false",&special);CHKERRQ(ierr);
4195dc0f0a4SBarry Smith   }
4205dc0f0a4SBarry Smith   if (!special) {
4215dc0f0a4SBarry Smith     PetscInt i;
4225dc0f0a4SBarry Smith 
4235dc0f0a4SBarry Smith     ierr    = PetscStrlen(value,&len);CHKERRQ(ierr);
4245dc0f0a4SBarry Smith     special = PETSC_TRUE;
4255dc0f0a4SBarry Smith     for (i=0; i<(int)len; i++) {
4265dc0f0a4SBarry Smith       if (!isdigit(value[i])) {
4275dc0f0a4SBarry Smith         special = PETSC_FALSE;
4285dc0f0a4SBarry Smith         break;
4295dc0f0a4SBarry Smith       }
4305dc0f0a4SBarry Smith     }
4315dc0f0a4SBarry Smith   }
4325dc0f0a4SBarry Smith 
4335dc0f0a4SBarry Smith   ierr = PetscStrcat(buff,"\"");CHKERRQ(ierr);
4345dc0f0a4SBarry Smith   ierr = PetscStrcat(buff,key);CHKERRQ(ierr);
4355dc0f0a4SBarry Smith   ierr = PetscStrcat(buff,"\":");CHKERRQ(ierr);
4365dc0f0a4SBarry Smith   if (!special) {
4375dc0f0a4SBarry Smith     ierr = PetscStrcat(buff,"\"");CHKERRQ(ierr);
4385dc0f0a4SBarry Smith   }
4395dc0f0a4SBarry Smith   ierr = PetscStrcat(buff,value);CHKERRQ(ierr);
4405dc0f0a4SBarry Smith   if (!special) {
4415dc0f0a4SBarry Smith     ierr = PetscStrcat(buff,"\"");CHKERRQ(ierr);
4425dc0f0a4SBarry Smith   }
4435dc0f0a4SBarry Smith   PetscFunctionReturn(0);
4445dc0f0a4SBarry Smith }
445