Actual source code: client.c
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: }
23: /*@C
24: PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.
26: Output Parameter:
27: . octx - the SSL_CTX to be passed to PetscHTTPSConnect
29: Level: advanced
31: If PETSc was ./configure -with-ssl-certificate requires the user have created a self-signed certificate with
32: $ saws/CA.pl -newcert (using the passphrase of password)
33: $ cat newkey.pem newcert.pem > sslclient.pem
35: and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
36: silly but it was all I could figure out.
38: .seealso: PetscSSLDestroyContext(), PetscHTTPSConnect(), PetscHTTPSRequest()
40: @*/
41: PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
42: {
43: SSL_CTX *ctx;
44: #if defined(PETSC_USE_SSL_CERTIFICATE)
45: char keyfile[PETSC_MAX_PATH_LEN];
46: PetscBool exists;
47: #endif
49: if (!bio_err) {
50: SSL_library_init();
51: SSL_load_error_strings();
52: bio_err = BIO_new_fp(stderr,BIO_NOCLOSE);
53: }
55: /* Set up a SIGPIPE handler */
56: signal(SIGPIPE,sigpipe_handle);
58: /* suggested at https://mta.openssl.org/pipermail/openssl-dev/2015-May/001449.html */
59: #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
60: ctx = SSL_CTX_new(TLS_client_method());
61: #else
62: ctx = SSL_CTX_new(SSLv23_client_method());
63: #endif
64: SSL_CTX_set_mode(ctx,SSL_MODE_AUTO_RETRY);
66: #if defined(PETSC_USE_SSL_CERTIFICATE)
67: /* Locate keyfile */
68: PetscStrcpy(keyfile,"sslclient.pem");
69: PetscTestFile(keyfile,'r',&exists);
70: if (!exists) {
71: PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);
72: PetscStrcat(keyfile,"/");
73: PetscStrcat(keyfile,"sslclient.pem");
74: PetscTestFile(keyfile,'r',&exists);
76: }
78: /* Load our keys and certificates*/
81: SSL_CTX_set_default_passwd_cb(ctx,password_cb);
83: #endif
85: *octx = ctx;
86: return 0;
87: }
89: /*@C
90: PetscSSLDestroyContext - frees a SSL_CTX obtained with PetscSSLInitializeContext()
92: Input Parameter:
93: . ctx - the SSL_CTX
95: Level: advanced
97: .seealso: PetscSSLInitializeContext(), PetscHTTPSConnect()
98: @*/
99: PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx)
100: {
101: SSL_CTX_free(ctx);
102: return 0;
103: }
105: static PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest)
106: {
107: char *request=0;
108: char contentlength[40],contenttype[80],*path,*host;
109: size_t request_len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0;
110: PetscBool flg;
112: PetscStrallocpy(url,&host);
113: PetscStrchr(host,'/',&path);
115: *path = 0;
116: PetscStrlen(host,&hostlen);
118: PetscStrchr(url,'/',&path);
119: PetscStrlen(path,&pathlen);
121: if (header) {
122: PetscStrendswith(header,"\r\n",&flg);
124: }
126: PetscStrlen(type,&typelen);
127: if (ctype) {
128: PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);
129: PetscStrlen(contenttype,&contenttypelen);
130: }
131: PetscStrlen(header,&headlen);
132: PetscStrlen(body,&bodylen);
133: PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);
134: PetscStrlen(contentlength,&contentlen);
136: /* Now construct our HTTP request */
137: request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
138: PetscMalloc1(request_len,&request);
139: PetscStrcpy(request,type);
140: PetscStrcat(request," ");
141: PetscStrcat(request,path);
142: PetscStrcat(request," HTTP/1.1\r\nHost: ");
143: PetscStrcat(request,host);
144: PetscFree(host);
145: PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");
146: PetscStrcat(request,header);
147: if (ctype) {
148: PetscStrcat(request,contenttype);
149: }
150: PetscStrcat(request,contentlength);
151: PetscStrcat(request,body);
152: PetscStrlen(request,&request_len);
153: PetscInfo(NULL,"HTTPS request follows: \n%s\n",request);
155: *outrequest = request;
156: return 0;
157: }
159: /*@C
160: PetscHTTPSRequest - Send a request to an HTTPS server
162: Input Parameters:
163: + type - either "POST" or "GET"
164: . url - URL of request host/path
165: . header - additional header information, may be NULL
166: . ctype - data type of body, for example application/json
167: . body - data to send to server
168: . ssl - obtained with PetscHTTPSConnect()
169: - buffsize - size of buffer
171: Output Parameter:
172: . buff - everything returned from server
174: Level: advanced
176: .seealso: PetscHTTPRequest(), PetscHTTPSConnect(), PetscSSLInitializeContext(), PetscSSLDestroyContext(), PetscPullJSONValue()
178: @*/
179: PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize)
180: {
181: char *request;
182: int r;
183: size_t request_len,len;
184: PetscBool foundbody = PETSC_FALSE;
186: PetscHTTPBuildRequest(type,url,header,ctype,body,&request);
187: PetscStrlen(request,&request_len);
189: r = SSL_write(ssl,request,(int)request_len);
190: switch (SSL_get_error(ssl,r)) {
191: case SSL_ERROR_NONE:
193: break;
194: default:
195: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem");
196: }
198: /* Now read the server's response, globus sends it in two chunks hence must read a second time if needed */
199: PetscArrayzero(buff,buffsize);
200: len = 0;
201: foundbody = PETSC_FALSE;
202: do {
203: char *clen;
204: int cl;
205: size_t nlen;
207: r = SSL_read(ssl,buff+len,(int)buffsize);
208: len += r;
209: switch (SSL_get_error(ssl,r)) {
210: case SSL_ERROR_NONE:
211: break;
212: case SSL_ERROR_ZERO_RETURN:
213: foundbody = PETSC_TRUE;
214: SSL_shutdown(ssl);
215: break;
216: case SSL_ERROR_SYSCALL:
217: foundbody = PETSC_TRUE;
218: break;
219: default:
220: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem");
221: }
223: PetscStrstr(buff,"Content-Length: ",&clen);
224: if (clen) {
225: clen += 15;
226: sscanf(clen,"%d",&cl);
227: if (!cl) foundbody = PETSC_TRUE;
228: else {
229: PetscStrstr(buff,"\r\n\r\n",&clen);
230: if (clen) {
231: PetscStrlen(clen,&nlen);
232: if (nlen-4 == (size_t) cl) foundbody = PETSC_TRUE;
233: }
234: }
235: } else {
236: /* if no content length than must leave because you don't know if you can read again */
237: foundbody = PETSC_TRUE;
238: }
239: } while (!foundbody);
240: PetscInfo(NULL,"HTTPS result follows: \n%s\n",buff);
242: SSL_free(ssl);
243: PetscFree(request);
244: return 0;
245: }
247: /*@C
248: PetscHTTPRequest - Send a request to an HTTP server
250: Input Parameters:
251: + type - either "POST" or "GET"
252: . url - URL of request host/path
253: . header - additional header information, may be NULL
254: . ctype - data type of body, for example application/json
255: . body - data to send to server
256: . sock - obtained with PetscOpenSocket()
257: - buffsize - size of buffer
259: Output Parameter:
260: . buff - everything returned from server
262: Level: advanced
264: .seealso: PetscHTTPSRequest(), PetscOpenSocket(), PetscHTTPSConnect(), PetscPullJSONValue()
265: @*/
266: PetscErrorCode PetscHTTPRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],int sock,char buff[],size_t buffsize)
267: {
268: char *request;
269: size_t request_len;
271: PetscHTTPBuildRequest(type,url,header,ctype,body,&request);
272: PetscStrlen(request,&request_len);
274: PetscBinaryWrite(sock,request,request_len,PETSC_CHAR);
275: PetscFree(request);
276: PetscBinaryRead(sock,buff,buffsize,NULL,PETSC_CHAR);
277: buff[buffsize-1] = 0;
278: PetscInfo(NULL,"HTTP result follows: \n%s\n",buff);
279: return 0;
280: }
282: /*@C
283: PetscHTTPSConnect - connect to a HTTPS server
285: Input Parameters:
286: + host - the name of the machine hosting the HTTPS server
287: . port - the port number where the server is hosting, usually 443
288: - ctx - value obtained with PetscSSLInitializeContext()
290: Output Parameters:
291: + sock - socket to connect
292: - ssl - the argument passed to PetscHTTPSRequest()
294: Level: advanced
296: .seealso: PetscOpenSocket(), PetscHTTPSRequest(), PetscSSLInitializeContext()
297: @*/
298: PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl)
299: {
300: BIO *sbio;
302: /* Connect the TCP socket*/
303: PetscOpenSocket(host,port,sock);
305: /* Connect the SSL socket */
306: *ssl = SSL_new(ctx);
307: sbio = BIO_new_socket(*sock,BIO_NOCLOSE);
308: SSL_set_bio(*ssl,sbio,sbio);
310: return 0;
311: }
313: /*@C
314: PetscPullJSONValue - Given a JSON response containing the substring with "key" : "value" where there may or not be spaces around the : returns the value.
316: Input Parameters:
317: + buff - the char array containing the possible values
318: . key - the key of the requested value
319: - valuelen - the length of the array to contain the value associated with the key
321: Output Parameters:
322: + value - the value obtained
323: - found - flag indicating if the value was found in the buff
325: Level: advanced
327: @*/
328: PetscErrorCode PetscPullJSONValue(const char buff[],const char key[],char value[],size_t valuelen,PetscBool *found)
329: {
330: char *v,*w;
331: char work[256];
332: size_t len;
334: PetscStrcpy(work,"\"");
335: PetscStrlcat(work,key,sizeof(work));
336: PetscStrcat(work,"\":");
337: PetscStrstr(buff,work,&v);
338: PetscStrlen(work,&len);
339: if (v) {
340: v += len;
341: } else {
342: work[len++-1] = 0;
343: PetscStrcat(work," :");
344: PetscStrstr(buff,work,&v);
345: if (!v) {
346: *found = PETSC_FALSE;
347: return 0;
348: }
349: v += len;
350: }
351: PetscStrchr(v,'\"',&v);
352: if (!v) {
353: *found = PETSC_FALSE;
354: return 0;
355: }
356: PetscStrchr(v+1,'\"',&w);
357: if (!w) {
358: *found = PETSC_FALSE;
359: return 0;
360: }
361: *found = PETSC_TRUE;
362: PetscStrncpy(value,v+1,PetscMin((size_t)(w-v),valuelen));
363: return 0;
364: }
366: #include <ctype.h>
368: /*@C
369: PetscPushJSONValue - Puts a "key" : "value" pair onto a string
371: Input Parameters:
372: + buffer - the char array where the value will be put
373: . key - the key value to be set
374: . value - the value associated with the key
375: - bufflen - the size of the buffer (currently ignored)
377: Level: advanced
379: Notes:
380: Ignores lengths so can cause buffer overflow
381: @*/
382: PetscErrorCode PetscPushJSONValue(char buff[],const char key[],const char value[],size_t bufflen)
383: {
384: size_t len;
385: PetscBool special;
387: PetscStrcmp(value,"null",&special);
388: if (!special) {
389: PetscStrcmp(value,"true",&special);
390: }
391: if (!special) {
392: PetscStrcmp(value,"false",&special);
393: }
394: if (!special) {
395: PetscInt i;
397: PetscStrlen(value,&len);
398: special = PETSC_TRUE;
399: for (i=0; i<(int)len; i++) {
400: if (!isdigit(value[i])) {
401: special = PETSC_FALSE;
402: break;
403: }
404: }
405: }
407: PetscStrcat(buff,"\"");
408: PetscStrcat(buff,key);
409: PetscStrcat(buff,"\":");
410: if (!special) {
411: PetscStrcat(buff,"\"");
412: }
413: PetscStrcat(buff,value);
414: if (!special) {
415: PetscStrcat(buff,"\"");
416: }
417: return 0;
418: }