xref: /petsc/src/sys/webclient/client.c (revision 7a3410ede202c5dd1a2e9ef229f2be7d9c36a0b5)
1b967cddfSBarry Smith 
20efc6a03SBarry Smith #include <petscwebclient.h>
3b967cddfSBarry Smith 
4b967cddfSBarry Smith static BIO *bio_err = NULL;
5b967cddfSBarry Smith 
6b967cddfSBarry Smith #define PASSWORD "password"
7b967cddfSBarry Smith 
84a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
9b967cddfSBarry Smith static int password_cb(char *buf,int num, int rwflag,void *userdata)
10b967cddfSBarry Smith {
11b967cddfSBarry Smith   if (num < strlen(PASSWORD)+1) return(0);
12b967cddfSBarry Smith   strcpy(buf,PASSWORD);
13b967cddfSBarry Smith   return(strlen(PASSWORD));
14b967cddfSBarry Smith }
15b967cddfSBarry Smith #endif
16b967cddfSBarry Smith 
17b967cddfSBarry Smith static void sigpipe_handle(int x)
18b967cddfSBarry Smith {
19b967cddfSBarry Smith }
20b967cddfSBarry Smith 
21b967cddfSBarry Smith #undef __FUNCT__
22b967cddfSBarry Smith #define __FUNCT__ "PetscSSLInitializeContext"
23b967cddfSBarry Smith /*
24b967cddfSBarry Smith     PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.
25b967cddfSBarry Smith 
264a285bdaSBarry Smith     If built with PETSC_USE_SSL_CERTIFICATE requires the user have created a self-signed certificate with
27b967cddfSBarry Smith 
28b967cddfSBarry Smith $    ./CA.pl  -newcert  (using the passphrase of password)
29b967cddfSBarry Smith $    cat newkey.pem newcert.pem > sslclient.pem
30b967cddfSBarry Smith 
31b967cddfSBarry Smith     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
32b967cddfSBarry Smith     silly but it was all I could figure out.
33b967cddfSBarry Smith 
34b967cddfSBarry Smith */
35b967cddfSBarry Smith PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
36b967cddfSBarry Smith {
37b967cddfSBarry Smith     SSL_CTX        *ctx;
384a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
39b967cddfSBarry Smith     char           keyfile[PETSC_MAX_PATH_LEN];
40b967cddfSBarry Smith     PetscBool      exists;
41b967cddfSBarry Smith     PetscErrorCode ierr;
42b967cddfSBarry Smith #endif
43b967cddfSBarry Smith 
44b967cddfSBarry Smith     PetscFunctionBegin;
45b967cddfSBarry Smith     if (!bio_err){
46b967cddfSBarry Smith       SSL_library_init();
47b967cddfSBarry Smith       SSL_load_error_strings();
48b967cddfSBarry Smith       bio_err = BIO_new_fp(stderr,BIO_NOCLOSE);
49b967cddfSBarry Smith     }
50b967cddfSBarry Smith 
51b967cddfSBarry Smith     /* Set up a SIGPIPE handler */
52b967cddfSBarry Smith     signal(SIGPIPE,sigpipe_handle);
53b967cddfSBarry Smith 
54d8dcb26dSBarry Smith     ctx  = SSL_CTX_new(SSLv23_method());
55b967cddfSBarry Smith 
564a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE)
57b967cddfSBarry Smith     /* Locate keyfile */
58b967cddfSBarry Smith     ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr);
59b967cddfSBarry Smith     ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr);
60b967cddfSBarry Smith     if (!exists) {
61b967cddfSBarry Smith       ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr);
62b967cddfSBarry Smith       ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr);
63b967cddfSBarry Smith       ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr);
64b967cddfSBarry Smith       ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr);
65b967cddfSBarry Smith       if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory");
66b967cddfSBarry Smith     }
67b967cddfSBarry Smith 
68b967cddfSBarry Smith     /* Load our keys and certificates*/
69b967cddfSBarry Smith     if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file");
70b967cddfSBarry Smith 
71b967cddfSBarry Smith     SSL_CTX_set_default_passwd_cb(ctx,password_cb);
72b967cddfSBarry Smith     if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file");
73b967cddfSBarry Smith #endif
74b967cddfSBarry Smith 
75b967cddfSBarry Smith     *octx = ctx;
76b967cddfSBarry Smith     PetscFunctionReturn(0);
77b967cddfSBarry Smith }
78b967cddfSBarry Smith 
79b967cddfSBarry Smith #undef __FUNCT__
80b967cddfSBarry Smith #define __FUNCT__ "PetscSSLDestroyContext"
81b967cddfSBarry Smith PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx)
82b967cddfSBarry Smith {
83b967cddfSBarry Smith   PetscFunctionBegin;
84b967cddfSBarry Smith   SSL_CTX_free(ctx);
85b967cddfSBarry Smith   PetscFunctionReturn(0);
86b967cddfSBarry Smith }
87b967cddfSBarry Smith 
88b967cddfSBarry Smith #undef __FUNCT__
8904102261SBarry Smith #define __FUNCT__ "PetscHTTPBuildRequest"
9004102261SBarry Smith PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest)
91b967cddfSBarry Smith {
92b967cddfSBarry Smith   char           *request=0;
9393e1d32fSBarry Smith   char           contentlength[40],contenttype[80],*path,*host;
94*7a3410edSBarry Smith   size_t         request_len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0;
95b967cddfSBarry Smith   PetscErrorCode ierr;
96b967cddfSBarry Smith   PetscBool      flg;
97b967cddfSBarry Smith 
98b967cddfSBarry Smith   PetscFunctionBegin;
9993e1d32fSBarry Smith   ierr = PetscStrallocpy(url,&host);CHKERRQ(ierr);
10093e1d32fSBarry Smith   ierr = PetscStrchr(host,'/',&path);CHKERRQ(ierr);
10193e1d32fSBarry Smith   if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url);
10293e1d32fSBarry Smith   ierr = PetscStrlen(host,&hostlen);CHKERRQ(ierr);
10393e1d32fSBarry Smith 
10493e1d32fSBarry Smith   ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr);
10593e1d32fSBarry Smith   ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr);
10693e1d32fSBarry Smith 
107b967cddfSBarry Smith   if (header) {
108b967cddfSBarry Smith     ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr);
109b967cddfSBarry Smith     if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n");
110b967cddfSBarry Smith   }
111b967cddfSBarry Smith 
112b967cddfSBarry Smith   ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr);
113b967cddfSBarry Smith   if (ctype) {
114b967cddfSBarry Smith     ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr);
115b967cddfSBarry Smith     ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr);
116b967cddfSBarry Smith   }
117b967cddfSBarry Smith   ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr);
118b967cddfSBarry Smith   ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr);
119b967cddfSBarry Smith   ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr);
120b967cddfSBarry Smith   ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr);
121b967cddfSBarry Smith 
122b967cddfSBarry Smith   /* Now construct our HTTP request */
12393e1d32fSBarry Smith   request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
124fe278a28SBarry Smith   ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr);
125b967cddfSBarry Smith   ierr = PetscStrcpy(request,type);CHKERRQ(ierr);
126b967cddfSBarry Smith   ierr = PetscStrcat(request," ");CHKERRQ(ierr);
12793e1d32fSBarry Smith   ierr = PetscStrcat(request,path);CHKERRQ(ierr);
12893e1d32fSBarry Smith   ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr);
12993e1d32fSBarry Smith   ierr = PetscStrcat(request,host);CHKERRQ(ierr);
13093e1d32fSBarry Smith   ierr = PetscFree(host);CHKERRQ(ierr);
13193e1d32fSBarry Smith   ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr);
132b967cddfSBarry Smith   ierr = PetscStrcat(request,header);CHKERRQ(ierr);
133b967cddfSBarry Smith   if (ctype) {
134b967cddfSBarry Smith     ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr);
135b967cddfSBarry Smith   }
136b967cddfSBarry Smith   ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr);
137b967cddfSBarry Smith   ierr = PetscStrcat(request,body);CHKERRQ(ierr);
138b967cddfSBarry Smith   ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr);
139b967cddfSBarry Smith   ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr);
140b967cddfSBarry Smith 
14104102261SBarry Smith   *outrequest = request;
14204102261SBarry Smith   PetscFunctionReturn(0);
14304102261SBarry Smith }
14404102261SBarry Smith 
14504102261SBarry Smith 
14604102261SBarry Smith #undef __FUNCT__
14704102261SBarry Smith #define __FUNCT__ "PetscHTTPSRequest"
14804102261SBarry Smith /*
14904102261SBarry Smith      PetscHTTPSRequest - Send a request to an HTTPS server
15004102261SBarry Smith 
15104102261SBarry Smith    Input Parameters:
15204102261SBarry Smith +   type - either "POST" or "GET"
15304102261SBarry Smith .   url -  URL of request host/path
15404102261SBarry Smith .   header - additional header information, may be NULL
15504102261SBarry Smith .   ctype - data type of body, for example application/json
15604102261SBarry Smith .   body - data to send to server
15704102261SBarry Smith .   ssl - obtained with PetscHTTPSConnect()
15804102261SBarry Smith -   buffsize - size of buffer
15904102261SBarry Smith 
16004102261SBarry Smith    Output Parameter:
16104102261SBarry Smith .   buff - everything returned from server
16204102261SBarry Smith  */
16304102261SBarry 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)
16404102261SBarry Smith {
16504102261SBarry Smith   char           *request;
16604102261SBarry Smith   int            r;
16704102261SBarry Smith   size_t         request_len,len;
16804102261SBarry Smith   PetscErrorCode ierr;
16904102261SBarry Smith 
17004102261SBarry Smith   PetscFunctionBegin;
17104102261SBarry Smith   ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr);
17204102261SBarry Smith   ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr);
17304102261SBarry Smith 
174d8dcb26dSBarry Smith   r = SSL_write(ssl,request,(int)request_len);
175b967cddfSBarry Smith   switch (SSL_get_error(ssl,r)){
176b967cddfSBarry Smith     case SSL_ERROR_NONE:
177d8dcb26dSBarry Smith       if (request_len != (size_t)r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket");
178b967cddfSBarry Smith       break;
179b967cddfSBarry Smith     default:
180b967cddfSBarry Smith       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem");
181b967cddfSBarry Smith   }
182b967cddfSBarry Smith 
183b967cddfSBarry Smith   /* Now read the server's response, assuming  that it's terminated by a close */
184b967cddfSBarry Smith   r = SSL_read(ssl,buff,(int)buffsize);
185b967cddfSBarry Smith   len = r;
186b967cddfSBarry Smith   switch (SSL_get_error(ssl,r)){
187b967cddfSBarry Smith   case SSL_ERROR_NONE:
188b967cddfSBarry Smith     break;
189b967cddfSBarry Smith   case SSL_ERROR_ZERO_RETURN:
190b967cddfSBarry Smith     SSL_shutdown(ssl);  /* ignore shutdown error message */
191b967cddfSBarry Smith     break;
192b967cddfSBarry Smith   case SSL_ERROR_SYSCALL:
193b967cddfSBarry Smith     break;
194b967cddfSBarry Smith   default:
195b967cddfSBarry Smith     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem");
196b967cddfSBarry Smith   }
197b967cddfSBarry Smith   buff[len] = 0; /* null terminate string */
198b967cddfSBarry Smith   ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr);
199b967cddfSBarry Smith 
200b967cddfSBarry Smith   SSL_free(ssl);
201b967cddfSBarry Smith   ierr = PetscFree(request);CHKERRQ(ierr);
202b967cddfSBarry Smith   PetscFunctionReturn(0);
203b967cddfSBarry Smith }
204b967cddfSBarry Smith 
205b967cddfSBarry Smith #undef __FUNCT__
20604102261SBarry Smith #define __FUNCT__ "PetscHTTPRequest"
20704102261SBarry Smith /*
20804102261SBarry Smith      PetscHTTPRequest - Send a request to an HTTP server
20904102261SBarry Smith 
21004102261SBarry Smith    Input Parameters:
21104102261SBarry Smith +   type - either "POST" or "GET"
21204102261SBarry Smith .   url -  URL of request host/path
21304102261SBarry Smith .   header - additional header information, may be NULL
21404102261SBarry Smith .   ctype - data type of body, for example application/json
21504102261SBarry Smith .   body - data to send to server
21604102261SBarry Smith .   sock - obtained with PetscOpenSocket()
21704102261SBarry Smith -   buffsize - size of buffer
21804102261SBarry Smith 
21904102261SBarry Smith    Output Parameter:
22004102261SBarry Smith .   buff - everything returned from server
22104102261SBarry Smith  */
22204102261SBarry 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)
22304102261SBarry Smith {
22404102261SBarry Smith   char           *request;
22504102261SBarry Smith   size_t         request_len;
22604102261SBarry Smith   PetscErrorCode ierr;
22704102261SBarry Smith 
22804102261SBarry Smith   PetscFunctionBegin;
22904102261SBarry Smith   ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr);
23004102261SBarry Smith   ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr);
23104102261SBarry Smith 
23204102261SBarry Smith   ierr = PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
23304102261SBarry Smith   ierr = PetscFree(request);CHKERRQ(ierr);
23404102261SBarry Smith   PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR);
23504102261SBarry Smith   buff[buffsize-1] = 0;
23604102261SBarry Smith   ierr = PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);CHKERRQ(ierr);
23704102261SBarry Smith   PetscFunctionReturn(0);
23804102261SBarry Smith }
23904102261SBarry Smith 
24004102261SBarry Smith 
24104102261SBarry Smith #undef __FUNCT__
242b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSConnect"
243b967cddfSBarry Smith PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl)
244b967cddfSBarry Smith {
245b967cddfSBarry Smith   BIO            *sbio;
246b967cddfSBarry Smith   PetscErrorCode ierr;
247b967cddfSBarry Smith 
248b967cddfSBarry Smith   PetscFunctionBegin;
249b967cddfSBarry Smith   /* Connect the TCP socket*/
250b967cddfSBarry Smith   ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr);
251b967cddfSBarry Smith 
252b967cddfSBarry Smith   /* Connect the SSL socket */
253b967cddfSBarry Smith   *ssl = SSL_new(ctx);
254b967cddfSBarry Smith   sbio = BIO_new_socket(*sock,BIO_NOCLOSE);
255b967cddfSBarry Smith   SSL_set_bio(*ssl,sbio,sbio);
256b967cddfSBarry Smith   if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error");
257b967cddfSBarry Smith   PetscFunctionReturn(0);
258b967cddfSBarry Smith }
259b967cddfSBarry Smith 
260