xref: /petsc/src/sys/webclient/client.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
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)
119371c9d4SSatish Balay static int password_cb(char *buf, int num, int rwflag, void *userdata) {
12b967cddfSBarry Smith   if (num < strlen(PASSWORD) + 1) return (0);
13b967cddfSBarry Smith   strcpy(buf, PASSWORD);
14b967cddfSBarry Smith   return (strlen(PASSWORD));
15b967cddfSBarry Smith }
16b967cddfSBarry Smith #endif
17b967cddfSBarry Smith 
189371c9d4SSatish Balay static void sigpipe_handle(int x) { }
19b967cddfSBarry Smith 
204683183fSBarry Smith /*@C
21b967cddfSBarry Smith     PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.
22b967cddfSBarry Smith 
234683183fSBarry Smith     Output Parameter:
244683183fSBarry Smith .   octx - the SSL_CTX to be passed to PetscHTTPSConnect
25b967cddfSBarry Smith 
264683183fSBarry Smith     Level: advanced
274683183fSBarry Smith 
284683183fSBarry Smith     If PETSc was ./configure -with-ssl-certificate requires the user have created a self-signed certificate with
2968e69593SBarry Smith $    saws/CA.pl  -newcert  (using the passphrase of password)
30b967cddfSBarry Smith $    cat newkey.pem newcert.pem > sslclient.pem
31b967cddfSBarry Smith 
32b967cddfSBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
33b967cddfSBarry Smith     silly but it was all I could figure out.
34b967cddfSBarry Smith 
35db781477SPatrick Sanan .seealso: `PetscSSLDestroyContext()`, `PetscHTTPSConnect()`, `PetscHTTPSRequest()`
364683183fSBarry Smith 
374683183fSBarry Smith @*/
389371c9d4SSatish Balay PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx) {
39b967cddfSBarry Smith   SSL_CTX *ctx;
404a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
41b967cddfSBarry Smith   char      keyfile[PETSC_MAX_PATH_LEN];
42b967cddfSBarry Smith   PetscBool exists;
43b967cddfSBarry Smith #endif
44b967cddfSBarry Smith 
45b967cddfSBarry Smith   PetscFunctionBegin;
46b967cddfSBarry Smith   if (!bio_err) {
47b967cddfSBarry Smith     SSL_library_init();
48b967cddfSBarry Smith     SSL_load_error_strings();
49b967cddfSBarry Smith     bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
50b967cddfSBarry Smith   }
51b967cddfSBarry Smith 
52b967cddfSBarry Smith   /* Set up a SIGPIPE handler */
53b967cddfSBarry Smith   signal(SIGPIPE, sigpipe_handle);
54b967cddfSBarry Smith 
55ecd1d7b8SBarry Smith /* suggested at https://mta.openssl.org/pipermail/openssl-dev/2015-May/001449.html */
56ecd1d7b8SBarry Smith #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
57ecd1d7b8SBarry Smith   ctx = SSL_CTX_new(TLS_client_method());
58ecd1d7b8SBarry Smith #else
59ecd1d7b8SBarry Smith   ctx = SSL_CTX_new(SSLv23_client_method());
60ecd1d7b8SBarry Smith #endif
615dc0f0a4SBarry Smith   SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
62b967cddfSBarry Smith 
634a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
64b967cddfSBarry Smith   /* Locate keyfile */
659566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy(keyfile, "sslclient.pem"));
669566063dSJacob Faibussowitsch   PetscCall(PetscTestFile(keyfile, 'r', &exists));
67b967cddfSBarry Smith   if (!exists) {
689566063dSJacob Faibussowitsch     PetscCall(PetscGetHomeDirectory(keyfile, PETSC_MAX_PATH_LEN));
699566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(keyfile, "/"));
709566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(keyfile, "sslclient.pem"));
719566063dSJacob Faibussowitsch     PetscCall(PetscTestFile(keyfile, 'r', &exists));
7228b400f6SJacob Faibussowitsch     PetscCheck(exists, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate sslclient.pem file in current directory or home directory");
73b967cddfSBarry Smith   }
74b967cddfSBarry Smith 
75b967cddfSBarry Smith   /* Load our keys and certificates*/
76cc73adaaSBarry Smith   PetscCheck(SSL_CTX_use_certificate_chain_file(ctx, keyfile), PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot read certificate file");
77b967cddfSBarry Smith 
78b967cddfSBarry Smith   SSL_CTX_set_default_passwd_cb(ctx, password_cb);
79cc73adaaSBarry Smith   PetscCheck(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM), PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot read key file");
80b967cddfSBarry Smith #endif
81b967cddfSBarry Smith 
82b967cddfSBarry Smith   *octx = ctx;
83b967cddfSBarry Smith   PetscFunctionReturn(0);
84b967cddfSBarry Smith }
85b967cddfSBarry Smith 
864683183fSBarry Smith /*@C
874683183fSBarry Smith      PetscSSLDestroyContext - frees a SSL_CTX obtained with PetscSSLInitializeContext()
884683183fSBarry Smith 
894683183fSBarry Smith      Input Parameter:
904683183fSBarry Smith .     ctx - the SSL_CTX
914683183fSBarry Smith 
924683183fSBarry Smith     Level: advanced
934683183fSBarry Smith 
94db781477SPatrick Sanan .seealso: `PetscSSLInitializeContext()`, `PetscHTTPSConnect()`
954683183fSBarry Smith @*/
969371c9d4SSatish Balay PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx) {
97b967cddfSBarry Smith   PetscFunctionBegin;
98b967cddfSBarry Smith   SSL_CTX_free(ctx);
99b967cddfSBarry Smith   PetscFunctionReturn(0);
100b967cddfSBarry Smith }
101b967cddfSBarry Smith 
1029371c9d4SSatish Balay static PetscErrorCode PetscHTTPBuildRequest(const char type[], const char url[], const char header[], const char ctype[], const char body[], char **outrequest) {
103b967cddfSBarry Smith   char     *request = 0;
10493e1d32fSBarry Smith   char      contentlength[40], contenttype[80], *path, *host;
1057a3410edSBarry Smith   size_t    request_len, headlen, bodylen, contentlen, pathlen, hostlen, typelen, contenttypelen = 0;
106b967cddfSBarry Smith   PetscBool flg;
107b967cddfSBarry Smith 
108b967cddfSBarry Smith   PetscFunctionBegin;
1099566063dSJacob Faibussowitsch   PetscCall(PetscStrallocpy(url, &host));
1109566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(host, '/', &path));
11128b400f6SJacob Faibussowitsch   PetscCheck(path, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "url must contain / it is %s", url);
112c245270aSBarry Smith   *path = 0;
1139566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(host, &hostlen));
11493e1d32fSBarry Smith 
1159566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(url, '/', &path));
1169566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(path, &pathlen));
11793e1d32fSBarry Smith 
118b967cddfSBarry Smith   if (header) {
1199566063dSJacob Faibussowitsch     PetscCall(PetscStrendswith(header, "\r\n", &flg));
120d8174014SToby Isaac     PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "header must end with \\r\\n");
121b967cddfSBarry Smith   }
122b967cddfSBarry Smith 
1239566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(type, &typelen));
124b967cddfSBarry Smith   if (ctype) {
1259566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(contenttype, 80, "Content-Type: %s\r\n", ctype));
1269566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(contenttype, &contenttypelen));
127b967cddfSBarry Smith   }
1289566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(header, &headlen));
1299566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(body, &bodylen));
1309566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(contentlength, 40, "Content-Length: %d\r\n\r\n", (int)bodylen));
1319566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(contentlength, &contentlen));
132b967cddfSBarry Smith 
133b967cddfSBarry Smith   /* Now construct our HTTP request */
13493e1d32fSBarry Smith   request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
1359566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(request_len, &request));
1369566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy(request, type));
1379566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request, " "));
1389566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request, path));
1399566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request, " HTTP/1.1\r\nHost: "));
1409566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request, host));
1419566063dSJacob Faibussowitsch   PetscCall(PetscFree(host));
1429566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request, "\r\nUser-Agent:PETScClient\r\n"));
1439566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request, header));
1441baa6e33SBarry Smith   if (ctype) PetscCall(PetscStrcat(request, contenttype));
1459566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request, contentlength));
1469566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(request, body));
1479566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
1489566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTPS request follows: \n%s\n", request));
149b967cddfSBarry Smith 
15004102261SBarry Smith   *outrequest = request;
15104102261SBarry Smith   PetscFunctionReturn(0);
15204102261SBarry Smith }
15304102261SBarry Smith 
1544683183fSBarry Smith /*@C
15504102261SBarry Smith      PetscHTTPSRequest - Send a request to an HTTPS server
15604102261SBarry Smith 
15704102261SBarry Smith    Input Parameters:
15804102261SBarry Smith +   type - either "POST" or "GET"
15904102261SBarry Smith .   url -  URL of request host/path
16004102261SBarry Smith .   header - additional header information, may be NULL
16104102261SBarry Smith .   ctype - data type of body, for example application/json
16204102261SBarry Smith .   body - data to send to server
16304102261SBarry Smith .   ssl - obtained with PetscHTTPSConnect()
16404102261SBarry Smith -   buffsize - size of buffer
16504102261SBarry Smith 
16604102261SBarry Smith    Output Parameter:
16704102261SBarry Smith .   buff - everything returned from server
1684683183fSBarry Smith 
1694683183fSBarry Smith     Level: advanced
1704683183fSBarry Smith 
171db781477SPatrick Sanan .seealso: `PetscHTTPRequest()`, `PetscHTTPSConnect()`, `PetscSSLInitializeContext()`, `PetscSSLDestroyContext()`, `PetscPullJSONValue()`
1724683183fSBarry Smith 
1734683183fSBarry Smith @*/
1749371c9d4SSatish Balay PetscErrorCode PetscHTTPSRequest(const char type[], const char url[], const char header[], const char ctype[], const char body[], SSL *ssl, char buff[], size_t buffsize) {
17504102261SBarry Smith   char     *request;
17604102261SBarry Smith   int       r;
17704102261SBarry Smith   size_t    request_len, len;
1785dc0f0a4SBarry Smith   PetscBool foundbody = PETSC_FALSE;
17904102261SBarry Smith 
18004102261SBarry Smith   PetscFunctionBegin;
1819566063dSJacob Faibussowitsch   PetscCall(PetscHTTPBuildRequest(type, url, header, ctype, body, &request));
1829566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
18304102261SBarry Smith 
184d8dcb26dSBarry Smith   r = SSL_write(ssl, request, (int)request_len);
185b967cddfSBarry Smith   switch (SSL_get_error(ssl, r)) {
1869371c9d4SSatish Balay   case SSL_ERROR_NONE: PetscCheck(request_len == (size_t)r, PETSC_COMM_SELF, PETSC_ERR_LIB, "Incomplete write to SSL socket"); break;
1879371c9d4SSatish Balay   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL socket write problem");
188b967cddfSBarry Smith   }
189b967cddfSBarry Smith 
1905dc0f0a4SBarry Smith   /* Now read the server's response, globus sends it in two chunks hence must read a second time if needed */
1919566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(buff, buffsize));
1925dc0f0a4SBarry Smith   len       = 0;
1935dc0f0a4SBarry Smith   foundbody = PETSC_FALSE;
1945dc0f0a4SBarry Smith   do {
1955dc0f0a4SBarry Smith     char  *clen;
1965dc0f0a4SBarry Smith     int    cl;
1975dc0f0a4SBarry Smith     size_t nlen;
1985dc0f0a4SBarry Smith 
1995dc0f0a4SBarry Smith     r = SSL_read(ssl, buff + len, (int)buffsize);
2005dc0f0a4SBarry Smith     len += r;
201b967cddfSBarry Smith     switch (SSL_get_error(ssl, r)) {
2029371c9d4SSatish Balay     case SSL_ERROR_NONE: break;
203b967cddfSBarry Smith     case SSL_ERROR_ZERO_RETURN:
2045dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2055dc0f0a4SBarry Smith       SSL_shutdown(ssl);
206b967cddfSBarry Smith       break;
2079371c9d4SSatish Balay     case SSL_ERROR_SYSCALL: foundbody = PETSC_TRUE; break;
2089371c9d4SSatish Balay     default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL read problem");
209b967cddfSBarry Smith     }
2105dc0f0a4SBarry Smith 
2119566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, "Content-Length: ", &clen));
2125dc0f0a4SBarry Smith     if (clen) {
2135dc0f0a4SBarry Smith       clen += 15;
2145dc0f0a4SBarry Smith       sscanf(clen, "%d", &cl);
2155dc0f0a4SBarry Smith       if (!cl) foundbody = PETSC_TRUE;
2165dc0f0a4SBarry Smith       else {
2179566063dSJacob Faibussowitsch         PetscCall(PetscStrstr(buff, "\r\n\r\n", &clen));
2185dc0f0a4SBarry Smith         if (clen) {
2199566063dSJacob Faibussowitsch           PetscCall(PetscStrlen(clen, &nlen));
2205dc0f0a4SBarry Smith           if (nlen - 4 == (size_t)cl) foundbody = PETSC_TRUE;
2215dc0f0a4SBarry Smith         }
2225dc0f0a4SBarry Smith       }
2235dc0f0a4SBarry Smith     } else {
2245dc0f0a4SBarry Smith       /* if no content length than must leave because you don't know if you can read again */
2255dc0f0a4SBarry Smith       foundbody = PETSC_TRUE;
2265dc0f0a4SBarry Smith     }
2275dc0f0a4SBarry Smith   } while (!foundbody);
2289566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTPS result follows: \n%s\n", buff));
229b967cddfSBarry Smith 
230b967cddfSBarry Smith   SSL_free(ssl);
2319566063dSJacob Faibussowitsch   PetscCall(PetscFree(request));
232b967cddfSBarry Smith   PetscFunctionReturn(0);
233b967cddfSBarry Smith }
234b967cddfSBarry Smith 
2354683183fSBarry Smith /*@C
23604102261SBarry Smith      PetscHTTPRequest - Send a request to an HTTP server
23704102261SBarry Smith 
23804102261SBarry Smith    Input Parameters:
23904102261SBarry Smith +   type - either "POST" or "GET"
24004102261SBarry Smith .   url -  URL of request host/path
24104102261SBarry Smith .   header - additional header information, may be NULL
24204102261SBarry Smith .   ctype - data type of body, for example application/json
24304102261SBarry Smith .   body - data to send to server
24404102261SBarry Smith .   sock - obtained with PetscOpenSocket()
24504102261SBarry Smith -   buffsize - size of buffer
24604102261SBarry Smith 
24704102261SBarry Smith    Output Parameter:
24804102261SBarry Smith .   buff - everything returned from server
2494683183fSBarry Smith 
2504683183fSBarry Smith     Level: advanced
2514683183fSBarry Smith 
252db781477SPatrick Sanan .seealso: `PetscHTTPSRequest()`, `PetscOpenSocket()`, `PetscHTTPSConnect()`, `PetscPullJSONValue()`
2534683183fSBarry Smith @*/
2549371c9d4SSatish Balay PetscErrorCode PetscHTTPRequest(const char type[], const char url[], const char header[], const char ctype[], const char body[], int sock, char buff[], size_t buffsize) {
25504102261SBarry Smith   char  *request;
25604102261SBarry Smith   size_t request_len;
25704102261SBarry Smith 
25804102261SBarry Smith   PetscFunctionBegin;
2599566063dSJacob Faibussowitsch   PetscCall(PetscHTTPBuildRequest(type, url, header, ctype, body, &request));
2609566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(request, &request_len));
26104102261SBarry Smith 
2629566063dSJacob Faibussowitsch   PetscCall(PetscBinaryWrite(sock, request, request_len, PETSC_CHAR));
2639566063dSJacob Faibussowitsch   PetscCall(PetscFree(request));
2649860990eSLisandro Dalcin   PetscBinaryRead(sock, buff, buffsize, NULL, PETSC_CHAR);
26504102261SBarry Smith   buff[buffsize - 1] = 0;
2669566063dSJacob Faibussowitsch   PetscCall(PetscInfo(NULL, "HTTP result follows: \n%s\n", buff));
26704102261SBarry Smith   PetscFunctionReturn(0);
26804102261SBarry Smith }
26904102261SBarry Smith 
2704683183fSBarry Smith /*@C
2714683183fSBarry Smith       PetscHTTPSConnect - connect to a HTTPS server
2724683183fSBarry Smith 
2734683183fSBarry Smith     Input Parameters:
2744683183fSBarry Smith +    host - the name of the machine hosting the HTTPS server
2754683183fSBarry Smith .    port - the port number where the server is hosting, usually 443
2764683183fSBarry Smith -    ctx - value obtained with PetscSSLInitializeContext()
2774683183fSBarry Smith 
2784683183fSBarry Smith     Output Parameters:
2794683183fSBarry Smith +    sock - socket to connect
2804683183fSBarry Smith -    ssl - the argument passed to PetscHTTPSRequest()
2814683183fSBarry Smith 
2824683183fSBarry Smith     Level: advanced
2834683183fSBarry Smith 
284db781477SPatrick Sanan .seealso: `PetscOpenSocket()`, `PetscHTTPSRequest()`, `PetscSSLInitializeContext()`
2854683183fSBarry Smith @*/
2869371c9d4SSatish Balay PetscErrorCode PetscHTTPSConnect(const char host[], int port, SSL_CTX *ctx, int *sock, SSL **ssl) {
287b967cddfSBarry Smith   BIO *sbio;
288b967cddfSBarry Smith 
289b967cddfSBarry Smith   PetscFunctionBegin;
290b967cddfSBarry Smith   /* Connect the TCP socket*/
2919566063dSJacob Faibussowitsch   PetscCall(PetscOpenSocket(host, port, sock));
292b967cddfSBarry Smith 
293b967cddfSBarry Smith   /* Connect the SSL socket */
294b967cddfSBarry Smith   *ssl = SSL_new(ctx);
295b967cddfSBarry Smith   sbio = BIO_new_socket(*sock, BIO_NOCLOSE);
296b967cddfSBarry Smith   SSL_set_bio(*ssl, sbio, sbio);
29708401ef6SPierre Jolivet   PetscCheck(SSL_connect(*ssl) > 0, PETSC_COMM_SELF, PETSC_ERR_LIB, "SSL connect error");
298b967cddfSBarry Smith   PetscFunctionReturn(0);
299b967cddfSBarry Smith }
300b967cddfSBarry Smith 
3014683183fSBarry Smith /*@C
3024683183fSBarry Smith      PetscPullJSONValue - Given a JSON response containing the substring with "key" : "value"  where there may or not be spaces around the : returns the value.
3034683183fSBarry Smith 
3044683183fSBarry Smith     Input Parameters:
3054683183fSBarry Smith +    buff - the char array containing the possible values
3064683183fSBarry Smith .    key - the key of the requested value
3074683183fSBarry Smith -    valuelen - the length of the array to contain the value associated with the key
3084683183fSBarry Smith 
3094683183fSBarry Smith     Output Parameters:
3104683183fSBarry Smith +    value - the value obtained
3114683183fSBarry Smith -    found - flag indicating if the value was found in the buff
3124683183fSBarry Smith 
3134683183fSBarry Smith     Level: advanced
3144683183fSBarry Smith 
3154683183fSBarry Smith @*/
3169371c9d4SSatish Balay PetscErrorCode PetscPullJSONValue(const char buff[], const char key[], char value[], size_t valuelen, PetscBool *found) {
31768e69593SBarry Smith   char  *v, *w;
31868e69593SBarry Smith   char   work[256];
31968e69593SBarry Smith   size_t len;
32068e69593SBarry Smith 
32168e69593SBarry Smith   PetscFunctionBegin;
3229566063dSJacob Faibussowitsch   PetscCall(PetscStrcpy(work, "\""));
3239566063dSJacob Faibussowitsch   PetscCall(PetscStrlcat(work, key, sizeof(work)));
3249566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(work, "\":"));
3259566063dSJacob Faibussowitsch   PetscCall(PetscStrstr(buff, work, &v));
3269566063dSJacob Faibussowitsch   PetscCall(PetscStrlen(work, &len));
32768e69593SBarry Smith   if (v) {
32868e69593SBarry Smith     v += len;
32968e69593SBarry Smith   } else {
33068e69593SBarry Smith     work[len++ - 1] = 0;
3319566063dSJacob Faibussowitsch     PetscCall(PetscStrcat(work, " :"));
3329566063dSJacob Faibussowitsch     PetscCall(PetscStrstr(buff, work, &v));
33368e69593SBarry Smith     if (!v) {
33468e69593SBarry Smith       *found = PETSC_FALSE;
33568e69593SBarry Smith       PetscFunctionReturn(0);
33668e69593SBarry Smith     }
33768e69593SBarry Smith     v += len;
33868e69593SBarry Smith   }
3399566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(v, '\"', &v));
34068e69593SBarry Smith   if (!v) {
34168e69593SBarry Smith     *found = PETSC_FALSE;
34268e69593SBarry Smith     PetscFunctionReturn(0);
34368e69593SBarry Smith   }
3449566063dSJacob Faibussowitsch   PetscCall(PetscStrchr(v + 1, '\"', &w));
34568e69593SBarry Smith   if (!w) {
34668e69593SBarry Smith     *found = PETSC_FALSE;
34768e69593SBarry Smith     PetscFunctionReturn(0);
34868e69593SBarry Smith   }
34968e69593SBarry Smith   *found = PETSC_TRUE;
3509566063dSJacob Faibussowitsch   PetscCall(PetscStrncpy(value, v + 1, PetscMin((size_t)(w - v), valuelen)));
35168e69593SBarry Smith   PetscFunctionReturn(0);
35268e69593SBarry Smith }
3535dc0f0a4SBarry Smith 
3545dc0f0a4SBarry Smith #include <ctype.h>
3555dc0f0a4SBarry Smith 
3564683183fSBarry Smith /*@C
3574683183fSBarry Smith     PetscPushJSONValue -  Puts a "key" : "value" pair onto a string
3585dc0f0a4SBarry Smith 
3594683183fSBarry Smith     Input Parameters:
3604683183fSBarry Smith +   buffer - the char array where the value will be put
3614683183fSBarry Smith .   key - the key value to be set
3624683183fSBarry Smith .   value - the value associated with the key
3634683183fSBarry Smith -   bufflen - the size of the buffer (currently ignored)
3644683183fSBarry Smith 
3654683183fSBarry Smith     Level: advanced
3664683183fSBarry Smith 
36795452b02SPatrick Sanan     Notes:
36895452b02SPatrick Sanan     Ignores lengths so can cause buffer overflow
3694683183fSBarry Smith @*/
3709371c9d4SSatish Balay PetscErrorCode PetscPushJSONValue(char buff[], const char key[], const char value[], size_t bufflen) {
3715dc0f0a4SBarry Smith   size_t    len;
3725dc0f0a4SBarry Smith   PetscBool special;
3735dc0f0a4SBarry Smith 
3745dc0f0a4SBarry Smith   PetscFunctionBegin;
3759566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(value, "null", &special));
376*48a46eb9SPierre Jolivet   if (!special) PetscCall(PetscStrcmp(value, "true", &special));
377*48a46eb9SPierre Jolivet   if (!special) PetscCall(PetscStrcmp(value, "false", &special));
3785dc0f0a4SBarry Smith   if (!special) {
3795dc0f0a4SBarry Smith     PetscInt i;
3805dc0f0a4SBarry Smith 
3819566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(value, &len));
3825dc0f0a4SBarry Smith     special = PETSC_TRUE;
3835dc0f0a4SBarry Smith     for (i = 0; i < (int)len; i++) {
3845dc0f0a4SBarry Smith       if (!isdigit(value[i])) {
3855dc0f0a4SBarry Smith         special = PETSC_FALSE;
3865dc0f0a4SBarry Smith         break;
3875dc0f0a4SBarry Smith       }
3885dc0f0a4SBarry Smith     }
3895dc0f0a4SBarry Smith   }
3905dc0f0a4SBarry Smith 
3919566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(buff, "\""));
3929566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(buff, key));
3939566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(buff, "\":"));
394*48a46eb9SPierre Jolivet   if (!special) PetscCall(PetscStrcat(buff, "\""));
3959566063dSJacob Faibussowitsch   PetscCall(PetscStrcat(buff, value));
396*48a46eb9SPierre Jolivet   if (!special) PetscCall(PetscStrcat(buff, "\""));
3975dc0f0a4SBarry Smith   PetscFunctionReturn(0);
3985dc0f0a4SBarry Smith }
399