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 28*68e69593SBarry Smith $ saws/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; 947a3410edSBarry 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); 102c245270aSBarry Smith *path = 0; 10393e1d32fSBarry Smith ierr = PetscStrlen(host,&hostlen);CHKERRQ(ierr); 10493e1d32fSBarry Smith 10593e1d32fSBarry Smith ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr); 10693e1d32fSBarry Smith ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr); 10793e1d32fSBarry Smith 108b967cddfSBarry Smith if (header) { 109b967cddfSBarry Smith ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 110b967cddfSBarry Smith if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 111b967cddfSBarry Smith } 112b967cddfSBarry Smith 113b967cddfSBarry Smith ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 114b967cddfSBarry Smith if (ctype) { 115b967cddfSBarry Smith ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 116b967cddfSBarry Smith ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 117b967cddfSBarry Smith } 118b967cddfSBarry Smith ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 119b967cddfSBarry Smith ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 120b967cddfSBarry Smith ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 121b967cddfSBarry Smith ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 122b967cddfSBarry Smith 123b967cddfSBarry Smith /* Now construct our HTTP request */ 12493e1d32fSBarry Smith request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1; 125fe278a28SBarry Smith ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 126b967cddfSBarry Smith ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 127b967cddfSBarry Smith ierr = PetscStrcat(request," ");CHKERRQ(ierr); 12893e1d32fSBarry Smith ierr = PetscStrcat(request,path);CHKERRQ(ierr); 12993e1d32fSBarry Smith ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr); 13093e1d32fSBarry Smith ierr = PetscStrcat(request,host);CHKERRQ(ierr); 13193e1d32fSBarry Smith ierr = PetscFree(host);CHKERRQ(ierr); 13293e1d32fSBarry Smith ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 133b967cddfSBarry Smith ierr = PetscStrcat(request,header);CHKERRQ(ierr); 134b967cddfSBarry Smith if (ctype) { 135b967cddfSBarry Smith ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 136b967cddfSBarry Smith } 137b967cddfSBarry Smith ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 138b967cddfSBarry Smith ierr = PetscStrcat(request,body);CHKERRQ(ierr); 139b967cddfSBarry Smith ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 140b967cddfSBarry Smith ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 141b967cddfSBarry Smith 14204102261SBarry Smith *outrequest = request; 14304102261SBarry Smith PetscFunctionReturn(0); 14404102261SBarry Smith } 14504102261SBarry Smith 14604102261SBarry Smith 14704102261SBarry Smith #undef __FUNCT__ 14804102261SBarry Smith #define __FUNCT__ "PetscHTTPSRequest" 14904102261SBarry Smith /* 15004102261SBarry Smith PetscHTTPSRequest - Send a request to an HTTPS server 15104102261SBarry Smith 15204102261SBarry Smith Input Parameters: 15304102261SBarry Smith + type - either "POST" or "GET" 15404102261SBarry Smith . url - URL of request host/path 15504102261SBarry Smith . header - additional header information, may be NULL 15604102261SBarry Smith . ctype - data type of body, for example application/json 15704102261SBarry Smith . body - data to send to server 15804102261SBarry Smith . ssl - obtained with PetscHTTPSConnect() 15904102261SBarry Smith - buffsize - size of buffer 16004102261SBarry Smith 16104102261SBarry Smith Output Parameter: 16204102261SBarry Smith . buff - everything returned from server 16304102261SBarry Smith */ 16404102261SBarry 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) 16504102261SBarry Smith { 16604102261SBarry Smith char *request; 16704102261SBarry Smith int r; 16804102261SBarry Smith size_t request_len,len; 16904102261SBarry Smith PetscErrorCode ierr; 17004102261SBarry Smith 17104102261SBarry Smith PetscFunctionBegin; 17204102261SBarry Smith ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 17304102261SBarry Smith ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 17404102261SBarry Smith 175d8dcb26dSBarry Smith r = SSL_write(ssl,request,(int)request_len); 176b967cddfSBarry Smith switch (SSL_get_error(ssl,r)){ 177b967cddfSBarry Smith case SSL_ERROR_NONE: 178d8dcb26dSBarry Smith if (request_len != (size_t)r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 179b967cddfSBarry Smith break; 180b967cddfSBarry Smith default: 181b967cddfSBarry Smith SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 182b967cddfSBarry Smith } 183b967cddfSBarry Smith 184b967cddfSBarry Smith /* Now read the server's response, assuming that it's terminated by a close */ 185b967cddfSBarry Smith r = SSL_read(ssl,buff,(int)buffsize); 186b967cddfSBarry Smith len = r; 187b967cddfSBarry Smith switch (SSL_get_error(ssl,r)){ 188b967cddfSBarry Smith case SSL_ERROR_NONE: 189b967cddfSBarry Smith break; 190b967cddfSBarry Smith case SSL_ERROR_ZERO_RETURN: 191b967cddfSBarry Smith SSL_shutdown(ssl); /* ignore shutdown error message */ 192b967cddfSBarry Smith break; 193b967cddfSBarry Smith case SSL_ERROR_SYSCALL: 194b967cddfSBarry Smith break; 195b967cddfSBarry Smith default: 196b967cddfSBarry Smith SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 197b967cddfSBarry Smith } 198b967cddfSBarry Smith buff[len] = 0; /* null terminate string */ 199b967cddfSBarry Smith ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 200b967cddfSBarry Smith 201b967cddfSBarry Smith SSL_free(ssl); 202b967cddfSBarry Smith ierr = PetscFree(request);CHKERRQ(ierr); 203b967cddfSBarry Smith PetscFunctionReturn(0); 204b967cddfSBarry Smith } 205b967cddfSBarry Smith 206b967cddfSBarry Smith #undef __FUNCT__ 20704102261SBarry Smith #define __FUNCT__ "PetscHTTPRequest" 20804102261SBarry Smith /* 20904102261SBarry Smith PetscHTTPRequest - Send a request to an HTTP server 21004102261SBarry Smith 21104102261SBarry Smith Input Parameters: 21204102261SBarry Smith + type - either "POST" or "GET" 21304102261SBarry Smith . url - URL of request host/path 21404102261SBarry Smith . header - additional header information, may be NULL 21504102261SBarry Smith . ctype - data type of body, for example application/json 21604102261SBarry Smith . body - data to send to server 21704102261SBarry Smith . sock - obtained with PetscOpenSocket() 21804102261SBarry Smith - buffsize - size of buffer 21904102261SBarry Smith 22004102261SBarry Smith Output Parameter: 22104102261SBarry Smith . buff - everything returned from server 22204102261SBarry Smith */ 22304102261SBarry 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) 22404102261SBarry Smith { 22504102261SBarry Smith char *request; 22604102261SBarry Smith size_t request_len; 22704102261SBarry Smith PetscErrorCode ierr; 22804102261SBarry Smith 22904102261SBarry Smith PetscFunctionBegin; 23004102261SBarry Smith ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 23104102261SBarry Smith ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 23204102261SBarry Smith 23304102261SBarry Smith ierr = PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr); 23404102261SBarry Smith ierr = PetscFree(request);CHKERRQ(ierr); 23504102261SBarry Smith PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR); 23604102261SBarry Smith buff[buffsize-1] = 0; 23704102261SBarry Smith ierr = PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);CHKERRQ(ierr); 23804102261SBarry Smith PetscFunctionReturn(0); 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*68e69593SBarry Smith #undef __FUNCT__ 261*68e69593SBarry Smith #define __FUNCT__ "PetscPullJSONValue" 262*68e69593SBarry Smith /* 263*68e69593SBarry Smith Given a JSON response containing the substring with "key" : "value" where there may or not be spaces around the : returns the value. 264*68e69593SBarry Smith */ 265*68e69593SBarry Smith PetscErrorCode PetscPullJSONValue(const char buff[],const char key[],char value[],size_t valuelen,PetscBool *found) 266*68e69593SBarry Smith { 267*68e69593SBarry Smith PetscErrorCode ierr; 268*68e69593SBarry Smith char *v,*w; 269*68e69593SBarry Smith char work[256]; 270*68e69593SBarry Smith size_t len; 271*68e69593SBarry Smith 272*68e69593SBarry Smith PetscFunctionBegin; 273*68e69593SBarry Smith ierr = PetscStrcpy(work,"\"");CHKERRQ(ierr); 274*68e69593SBarry Smith ierr = PetscStrncat(work,key,250);CHKERRQ(ierr); 275*68e69593SBarry Smith ierr = PetscStrcat(work,"\":");CHKERRQ(ierr); 276*68e69593SBarry Smith ierr = PetscStrstr(buff,work,&v);CHKERRQ(ierr); 277*68e69593SBarry Smith ierr = PetscStrlen(work,&len);CHKERRQ(ierr); 278*68e69593SBarry Smith if (v) { 279*68e69593SBarry Smith v += len; 280*68e69593SBarry Smith } else { 281*68e69593SBarry Smith work[len++-1] = 0; 282*68e69593SBarry Smith ierr = PetscStrcat(work," :");CHKERRQ(ierr); 283*68e69593SBarry Smith ierr = PetscStrstr(buff,work,&v);CHKERRQ(ierr); 284*68e69593SBarry Smith if (!v) { 285*68e69593SBarry Smith *found = PETSC_FALSE; 286*68e69593SBarry Smith PetscFunctionReturn(0); 287*68e69593SBarry Smith } 288*68e69593SBarry Smith v += len; 289*68e69593SBarry Smith } 290*68e69593SBarry Smith ierr = PetscStrchr(v,'\"',&v);CHKERRQ(ierr); 291*68e69593SBarry Smith if (!v) { 292*68e69593SBarry Smith *found = PETSC_FALSE; 293*68e69593SBarry Smith PetscFunctionReturn(0); 294*68e69593SBarry Smith } 295*68e69593SBarry Smith ierr = PetscStrchr(v+1,'\"',&w);CHKERRQ(ierr); 296*68e69593SBarry Smith if (!w) { 297*68e69593SBarry Smith *found = PETSC_FALSE; 298*68e69593SBarry Smith PetscFunctionReturn(0); 299*68e69593SBarry Smith } 300*68e69593SBarry Smith *found = PETSC_TRUE; 301*68e69593SBarry Smith ierr = PetscStrncpy(value,v+1,PetscMin(w-v,valuelen));CHKERRQ(ierr); 302*68e69593SBarry Smith PetscFunctionReturn(0); 303*68e69593SBarry Smith } 304