xref: /petsc/src/sys/webclient/client.c (revision d817401416fe7522c08df98fd1821bb4e0177fd0)
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 
234683183fSBarry Smith /*@C
24b967cddfSBarry Smith     PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.
25b967cddfSBarry Smith 
264683183fSBarry Smith     Output Parameter:
274683183fSBarry Smith .   octx - the SSL_CTX to be passed to PetscHTTPSConnect
28b967cddfSBarry Smith 
294683183fSBarry Smith     Level: advanced
304683183fSBarry Smith 
314683183fSBarry Smith     If PETSc was ./configure -with-ssl-certificate requires the user have created a self-signed certificate with
3268e69593SBarry Smith $    saws/CA.pl  -newcert  (using the passphrase of password)
33b967cddfSBarry Smith $    cat newkey.pem newcert.pem > sslclient.pem
34b967cddfSBarry Smith 
35b967cddfSBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
36b967cddfSBarry Smith     silly but it was all I could figure out.
37b967cddfSBarry Smith 
38db781477SPatrick Sanan .seealso: `PetscSSLDestroyContext()`, `PetscHTTPSConnect()`, `PetscHTTPSRequest()`
394683183fSBarry Smith 
404683183fSBarry Smith @*/
41b967cddfSBarry Smith PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
42b967cddfSBarry Smith {
43b967cddfSBarry Smith     SSL_CTX        *ctx;
444a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
45b967cddfSBarry Smith     char           keyfile[PETSC_MAX_PATH_LEN];
46b967cddfSBarry Smith     PetscBool      exists;
47b967cddfSBarry Smith #endif
48b967cddfSBarry Smith 
49b967cddfSBarry Smith     PetscFunctionBegin;
50b967cddfSBarry Smith     if (!bio_err) {
51b967cddfSBarry Smith       SSL_library_init();
52b967cddfSBarry Smith       SSL_load_error_strings();
53b967cddfSBarry Smith       bio_err = BIO_new_fp(stderr,BIO_NOCLOSE);
54b967cddfSBarry Smith     }
55b967cddfSBarry Smith 
56b967cddfSBarry Smith     /* Set up a SIGPIPE handler */
57b967cddfSBarry Smith     signal(SIGPIPE,sigpipe_handle);
58b967cddfSBarry Smith 
59ecd1d7b8SBarry Smith /* suggested at https://mta.openssl.org/pipermail/openssl-dev/2015-May/001449.html */
60ecd1d7b8SBarry Smith #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
61ecd1d7b8SBarry Smith     ctx  = SSL_CTX_new(TLS_client_method());
62ecd1d7b8SBarry Smith #else
63ecd1d7b8SBarry Smith     ctx  = SSL_CTX_new(SSLv23_client_method());
64ecd1d7b8SBarry Smith #endif
655dc0f0a4SBarry Smith     SSL_CTX_set_mode(ctx,SSL_MODE_AUTO_RETRY);
66b967cddfSBarry Smith 
674a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
68b967cddfSBarry Smith     /* Locate keyfile */
699566063dSJacob Faibussowitsch     PetscCall(PetscStrcpy(keyfile,"sslclient.pem"));
709566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(keyfile,'r',&exists));
71b967cddfSBarry Smith     if (!exists) {
729566063dSJacob Faibussowitsch       PetscCall(PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN));
739566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(keyfile,"/"));
749566063dSJacob Faibussowitsch       PetscCall(PetscStrcat(keyfile,"sslclient.pem"));
759566063dSJacob Faibussowitsch       PetscCall(PetscTestFile(keyfile,'r',&exists));
7628b400f6SJacob Faibussowitsch       PetscCheck(exists,PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory");
77b967cddfSBarry Smith     }
78b967cddfSBarry Smith 
79b967cddfSBarry Smith     /* Load our keys and certificates*/
80cc73adaaSBarry Smith     PetscCheck(SSL_CTX_use_certificate_chain_file(ctx,keyfile),PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file");
81b967cddfSBarry Smith 
82b967cddfSBarry Smith     SSL_CTX_set_default_passwd_cb(ctx,password_cb);
83cc73adaaSBarry Smith     PetscCheck(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM),PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file");
84b967cddfSBarry Smith #endif
85b967cddfSBarry Smith 
86b967cddfSBarry Smith     *octx = ctx;
87b967cddfSBarry Smith     PetscFunctionReturn(0);
88b967cddfSBarry Smith }
89b967cddfSBarry Smith 
904683183fSBarry Smith /*@C
914683183fSBarry Smith      PetscSSLDestroyContext - frees a SSL_CTX obtained with PetscSSLInitializeContext()
924683183fSBarry Smith 
934683183fSBarry Smith      Input Parameter:
944683183fSBarry Smith .     ctx - the SSL_CTX
954683183fSBarry Smith 
964683183fSBarry Smith     Level: advanced
974683183fSBarry Smith 
98db781477SPatrick Sanan .seealso: `PetscSSLInitializeContext()`, `PetscHTTPSConnect()`
994683183fSBarry 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 
1074683183fSBarry Smith static PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest)
108b967cddfSBarry Smith {
109b967cddfSBarry Smith   char           *request=0;
11093e1d32fSBarry Smith   char           contentlength[40],contenttype[80],*path,*host;
1117a3410edSBarry Smith   size_t         request_len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0;
112b967cddfSBarry Smith   PetscBool      flg;
113b967cddfSBarry Smith 
114b967cddfSBarry Smith   PetscFunctionBegin;
1159566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(url,&host));
1169566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(host,'/',&path));
11728b400f6SJacob Faibussowitsch   PetscCheck(path,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url);
118c245270aSBarry Smith   *path = 0;
1199566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(host,&hostlen));
12093e1d32fSBarry Smith 
1219566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(url,'/',&path));
1229566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(path,&pathlen));
12393e1d32fSBarry Smith 
124b967cddfSBarry Smith   if (header) {
1259566063dSJacob Faibussowitsch     PetscCall(PetscStrendswith(header,"\r\n",&flg));
126*d8174014SToby Isaac     PetscCheck(flg,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n");
127b967cddfSBarry Smith   }
128b967cddfSBarry Smith 
1299566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(type,&typelen));
130b967cddfSBarry Smith   if (ctype) {
1319566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype));
1329566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(contenttype,&contenttypelen));
133b967cddfSBarry Smith   }
1349566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(header,&headlen));
1359566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(body,&bodylen));
1369566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen));
1379566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(contentlength,&contentlen));
138b967cddfSBarry Smith 
139b967cddfSBarry Smith   /* Now construct our HTTP request */
14093e1d32fSBarry Smith   request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
1419566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(request_len,&request));
1429566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy(request,type));
1439566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request," "));
1449566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request,path));
1459566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request," HTTP/1.1\r\nHost: "));
1469566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request,host));
1479566063dSJacob Faibussowitsch   PetscCall(PetscFree(host));
1489566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n"));
1499566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request,header));
150b967cddfSBarry Smith   if (ctype) {
1519566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(request,contenttype));
152b967cddfSBarry Smith   }
1539566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request,contentlength));
1549566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request,body));
1559566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request,&request_len));
1569566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL,"HTTPS request follows: \n%s\n",request));
157b967cddfSBarry Smith 
15804102261SBarry Smith   *outrequest = request;
15904102261SBarry Smith   PetscFunctionReturn(0);
16004102261SBarry Smith }
16104102261SBarry Smith 
1624683183fSBarry Smith /*@C
16304102261SBarry Smith      PetscHTTPSRequest - Send a request to an HTTPS server
16404102261SBarry Smith 
16504102261SBarry Smith    Input Parameters:
16604102261SBarry Smith +   type - either "POST" or "GET"
16704102261SBarry Smith .   url -  URL of request host/path
16804102261SBarry Smith .   header - additional header information, may be NULL
16904102261SBarry Smith .   ctype - data type of body, for example application/json
17004102261SBarry Smith .   body - data to send to server
17104102261SBarry Smith .   ssl - obtained with PetscHTTPSConnect()
17204102261SBarry Smith -   buffsize - size of buffer
17304102261SBarry Smith 
17404102261SBarry Smith    Output Parameter:
17504102261SBarry Smith .   buff - everything returned from server
1764683183fSBarry Smith 
1774683183fSBarry Smith     Level: advanced
1784683183fSBarry Smith 
179db781477SPatrick Sanan .seealso: `PetscHTTPRequest()`, `PetscHTTPSConnect()`, `PetscSSLInitializeContext()`, `PetscSSLDestroyContext()`, `PetscPullJSONValue()`
1804683183fSBarry Smith 
1814683183fSBarry Smith @*/
18204102261SBarry 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)
18304102261SBarry Smith {
18404102261SBarry Smith   char           *request;
18504102261SBarry Smith   int            r;
18604102261SBarry Smith   size_t         request_len,len;
1875dc0f0a4SBarry Smith   PetscBool      foundbody = PETSC_FALSE;
18804102261SBarry Smith 
18904102261SBarry Smith   PetscFunctionBegin;
1909566063dSJacob Faibussowitsch   PetscCall(PetscHTTPBuildRequest(type,url,header,ctype,body,&request));
1919566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request,&request_len));
19204102261SBarry Smith 
193d8dcb26dSBarry Smith   r = SSL_write(ssl,request,(int)request_len);
194b967cddfSBarry Smith   switch (SSL_get_error(ssl,r)) {
195b967cddfSBarry Smith     case SSL_ERROR_NONE:
196cc73adaaSBarry Smith       PetscCheck(request_len == (size_t)r,PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket");
197b967cddfSBarry Smith       break;
198b967cddfSBarry Smith     default:
199b967cddfSBarry Smith       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem");
200b967cddfSBarry Smith   }
201b967cddfSBarry Smith 
2025dc0f0a4SBarry Smith   /* Now read the server's response, globus sends it in two chunks hence must read a second time if needed */
2039566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(buff,buffsize));
2045dc0f0a4SBarry Smith   len       = 0;
2055dc0f0a4SBarry Smith   foundbody = PETSC_FALSE;
2065dc0f0a4SBarry Smith   do {
2075dc0f0a4SBarry Smith     char   *clen;
2085dc0f0a4SBarry Smith     int    cl;
2095dc0f0a4SBarry Smith     size_t nlen;
2105dc0f0a4SBarry Smith 
2115dc0f0a4SBarry Smith     r = SSL_read(ssl,buff+len,(int)buffsize);
2125dc0f0a4SBarry Smith     len += r;
213b967cddfSBarry Smith     switch (SSL_get_error(ssl,r)) {
214b967cddfSBarry Smith     case SSL_ERROR_NONE:
215b967cddfSBarry Smith       break;
216b967cddfSBarry Smith     case SSL_ERROR_ZERO_RETURN:
2175dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2185dc0f0a4SBarry Smith       SSL_shutdown(ssl);
219b967cddfSBarry Smith       break;
220b967cddfSBarry Smith     case SSL_ERROR_SYSCALL:
2215dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
222b967cddfSBarry Smith       break;
223b967cddfSBarry Smith     default:
224b967cddfSBarry Smith       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem");
225b967cddfSBarry Smith     }
2265dc0f0a4SBarry Smith 
2279566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff,"Content-Length: ",&clen));
2285dc0f0a4SBarry Smith     if (clen) {
2295dc0f0a4SBarry Smith       clen += 15;
2305dc0f0a4SBarry Smith       sscanf(clen,"%d",&cl);
2315dc0f0a4SBarry Smith       if (!cl) foundbody = PETSC_TRUE;
2325dc0f0a4SBarry Smith       else {
2339566063dSJacob Faibussowitsch         PetscCall(PetscStrstr(buff,"\r\n\r\n",&clen));
2345dc0f0a4SBarry Smith         if (clen) {
2359566063dSJacob Faibussowitsch           PetscCall(PetscStrlen(clen,&nlen));
2365dc0f0a4SBarry Smith           if (nlen-4 == (size_t) cl) foundbody = PETSC_TRUE;
2375dc0f0a4SBarry Smith         }
2385dc0f0a4SBarry Smith       }
2395dc0f0a4SBarry Smith     } else {
2405dc0f0a4SBarry Smith       /* if no content length than must leave because you don't know if you can read again */
2415dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2425dc0f0a4SBarry Smith     }
2435dc0f0a4SBarry Smith   } while (!foundbody);
2449566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL,"HTTPS result follows: \n%s\n",buff));
245b967cddfSBarry Smith 
246b967cddfSBarry Smith   SSL_free(ssl);
2479566063dSJacob Faibussowitsch   PetscCall(PetscFree(request));
248b967cddfSBarry Smith   PetscFunctionReturn(0);
249b967cddfSBarry Smith }
250b967cddfSBarry Smith 
2514683183fSBarry Smith /*@C
25204102261SBarry Smith      PetscHTTPRequest - Send a request to an HTTP server
25304102261SBarry Smith 
25404102261SBarry Smith    Input Parameters:
25504102261SBarry Smith +   type - either "POST" or "GET"
25604102261SBarry Smith .   url -  URL of request host/path
25704102261SBarry Smith .   header - additional header information, may be NULL
25804102261SBarry Smith .   ctype - data type of body, for example application/json
25904102261SBarry Smith .   body - data to send to server
26004102261SBarry Smith .   sock - obtained with PetscOpenSocket()
26104102261SBarry Smith -   buffsize - size of buffer
26204102261SBarry Smith 
26304102261SBarry Smith    Output Parameter:
26404102261SBarry Smith .   buff - everything returned from server
2654683183fSBarry Smith 
2664683183fSBarry Smith     Level: advanced
2674683183fSBarry Smith 
268db781477SPatrick Sanan .seealso: `PetscHTTPSRequest()`, `PetscOpenSocket()`, `PetscHTTPSConnect()`, `PetscPullJSONValue()`
2694683183fSBarry Smith @*/
27004102261SBarry 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)
27104102261SBarry Smith {
27204102261SBarry Smith   char           *request;
27304102261SBarry Smith   size_t         request_len;
27404102261SBarry Smith 
27504102261SBarry Smith   PetscFunctionBegin;
2769566063dSJacob Faibussowitsch   PetscCall(PetscHTTPBuildRequest(type,url,header,ctype,body,&request));
2779566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request,&request_len));
27804102261SBarry Smith 
2799566063dSJacob Faibussowitsch   PetscCall(PetscBinaryWrite(sock,request,request_len,PETSC_CHAR));
2809566063dSJacob Faibussowitsch   PetscCall(PetscFree(request));
2819860990eSLisandro Dalcin   PetscBinaryRead(sock,buff,buffsize,NULL,PETSC_CHAR);
28204102261SBarry Smith   buff[buffsize-1] = 0;
2839566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL,"HTTP result follows: \n%s\n",buff));
28404102261SBarry Smith   PetscFunctionReturn(0);
28504102261SBarry Smith }
28604102261SBarry Smith 
2874683183fSBarry Smith /*@C
2884683183fSBarry Smith       PetscHTTPSConnect - connect to a HTTPS server
2894683183fSBarry Smith 
2904683183fSBarry Smith     Input Parameters:
2914683183fSBarry Smith +    host - the name of the machine hosting the HTTPS server
2924683183fSBarry Smith .    port - the port number where the server is hosting, usually 443
2934683183fSBarry Smith -    ctx - value obtained with PetscSSLInitializeContext()
2944683183fSBarry Smith 
2954683183fSBarry Smith     Output Parameters:
2964683183fSBarry Smith +    sock - socket to connect
2974683183fSBarry Smith -    ssl - the argument passed to PetscHTTPSRequest()
2984683183fSBarry Smith 
2994683183fSBarry Smith     Level: advanced
3004683183fSBarry Smith 
301db781477SPatrick Sanan .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`
3024683183fSBarry Smith @*/
303b967cddfSBarry Smith PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl)
304b967cddfSBarry Smith {
305b967cddfSBarry Smith   BIO            *sbio;
306b967cddfSBarry Smith 
307b967cddfSBarry Smith   PetscFunctionBegin;
308b967cddfSBarry Smith   /* Connect the TCP socket*/
3099566063dSJacob Faibussowitsch   PetscCall(PetscOpenSocket(host,port,sock));
310b967cddfSBarry Smith 
311b967cddfSBarry Smith   /* Connect the SSL socket */
312b967cddfSBarry Smith   *ssl = SSL_new(ctx);
313b967cddfSBarry Smith   sbio = BIO_new_socket(*sock,BIO_NOCLOSE);
314b967cddfSBarry Smith   SSL_set_bio(*ssl,sbio,sbio);
31508401ef6SPierre Jolivet   PetscCheck(SSL_connect(*ssl) > 0,PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error");
316b967cddfSBarry Smith   PetscFunctionReturn(0);
317b967cddfSBarry Smith }
318b967cddfSBarry Smith 
3194683183fSBarry Smith /*@C
3204683183fSBarry Smith      PetscPullJSONValue - Given a JSON response containing the substring with "key" : "value"  where there may or not be spaces around the : returns the value.
3214683183fSBarry Smith 
3224683183fSBarry Smith     Input Parameters:
3234683183fSBarry Smith +    buff - the char array containing the possible values
3244683183fSBarry Smith .    key - the key of the requested value
3254683183fSBarry Smith -    valuelen - the length of the array to contain the value associated with the key
3264683183fSBarry Smith 
3274683183fSBarry Smith     Output Parameters:
3284683183fSBarry Smith +    value - the value obtained
3294683183fSBarry Smith -    found - flag indicating if the value was found in the buff
3304683183fSBarry Smith 
3314683183fSBarry Smith     Level: advanced
3324683183fSBarry Smith 
3334683183fSBarry Smith @*/
33468e69593SBarry Smith PetscErrorCode PetscPullJSONValue(const char buff[],const char key[],char value[],size_t valuelen,PetscBool *found)
33568e69593SBarry Smith {
33668e69593SBarry Smith   char           *v,*w;
33768e69593SBarry Smith   char           work[256];
33868e69593SBarry Smith   size_t         len;
33968e69593SBarry Smith 
34068e69593SBarry Smith   PetscFunctionBegin;
3419566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy(work,"\""));
3429566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(work,key,sizeof(work)));
3439566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(work,"\":"));
3449566063dSJacob Faibussowitsch   PetscCall(PetscStrstr(buff,work,&v));
3459566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(work,&len));
34668e69593SBarry Smith   if (v) {
34768e69593SBarry Smith     v += len;
34868e69593SBarry Smith   } else {
34968e69593SBarry Smith     work[len++-1] = 0;
3509566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(work," :"));
3519566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff,work,&v));
35268e69593SBarry Smith     if (!v) {
35368e69593SBarry Smith       *found = PETSC_FALSE;
35468e69593SBarry Smith       PetscFunctionReturn(0);
35568e69593SBarry Smith     }
35668e69593SBarry Smith     v += len;
35768e69593SBarry Smith   }
3589566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(v,'\"',&v));
35968e69593SBarry Smith   if (!v) {
36068e69593SBarry Smith     *found = PETSC_FALSE;
36168e69593SBarry Smith     PetscFunctionReturn(0);
36268e69593SBarry Smith   }
3639566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(v+1,'\"',&w));
36468e69593SBarry Smith   if (!w) {
36568e69593SBarry Smith     *found = PETSC_FALSE;
36668e69593SBarry Smith     PetscFunctionReturn(0);
36768e69593SBarry Smith   }
36868e69593SBarry Smith   *found = PETSC_TRUE;
3699566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(value,v+1,PetscMin((size_t)(w-v),valuelen)));
37068e69593SBarry Smith   PetscFunctionReturn(0);
37168e69593SBarry Smith }
3725dc0f0a4SBarry Smith 
3735dc0f0a4SBarry Smith #include <ctype.h>
3745dc0f0a4SBarry Smith 
3754683183fSBarry Smith /*@C
3764683183fSBarry Smith     PetscPushJSONValue -  Puts a "key" : "value" pair onto a string
3775dc0f0a4SBarry Smith 
3784683183fSBarry Smith     Input Parameters:
3794683183fSBarry Smith +   buffer - the char array where the value will be put
3804683183fSBarry Smith .   key - the key value to be set
3814683183fSBarry Smith .   value - the value associated with the key
3824683183fSBarry Smith -   bufflen - the size of the buffer (currently ignored)
3834683183fSBarry Smith 
3844683183fSBarry Smith     Level: advanced
3854683183fSBarry Smith 
38695452b02SPatrick Sanan     Notes:
38795452b02SPatrick Sanan     Ignores lengths so can cause buffer overflow
3884683183fSBarry Smith @*/
3895dc0f0a4SBarry Smith PetscErrorCode PetscPushJSONValue(char buff[],const char key[],const char value[],size_t bufflen)
3905dc0f0a4SBarry Smith {
3915dc0f0a4SBarry Smith   size_t         len;
3925dc0f0a4SBarry Smith   PetscBool      special;
3935dc0f0a4SBarry Smith 
3945dc0f0a4SBarry Smith   PetscFunctionBegin;
3959566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(value,"null",&special));
3965dc0f0a4SBarry Smith   if (!special) {
3979566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(value,"true",&special));
3985dc0f0a4SBarry Smith   }
3995dc0f0a4SBarry Smith   if (!special) {
4009566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(value,"false",&special));
4015dc0f0a4SBarry Smith   }
4025dc0f0a4SBarry Smith   if (!special) {
4035dc0f0a4SBarry Smith     PetscInt i;
4045dc0f0a4SBarry Smith 
4059566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(value,&len));
4065dc0f0a4SBarry Smith     special = PETSC_TRUE;
4075dc0f0a4SBarry Smith     for (i=0; i<(int)len; i++) {
4085dc0f0a4SBarry Smith       if (!isdigit(value[i])) {
4095dc0f0a4SBarry Smith         special = PETSC_FALSE;
4105dc0f0a4SBarry Smith         break;
4115dc0f0a4SBarry Smith       }
4125dc0f0a4SBarry Smith     }
4135dc0f0a4SBarry Smith   }
4145dc0f0a4SBarry Smith 
4159566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(buff,"\""));
4169566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(buff,key));
4179566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(buff,"\":"));
4185dc0f0a4SBarry Smith   if (!special) {
4199566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(buff,"\""));
4205dc0f0a4SBarry Smith   }
4219566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(buff,value));
4225dc0f0a4SBarry Smith   if (!special) {
4239566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(buff,"\""));
4245dc0f0a4SBarry Smith   }
4255dc0f0a4SBarry Smith   PetscFunctionReturn(0);
4265dc0f0a4SBarry Smith }
427