Actual source code: client.c
petsc-3.7.1 2016-05-15
Report Typos and Errors

      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: }

     25: /*
     26:     PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests.

     28:     If built with PETSC_USE_SSL_CERTIFICATE requires the user have created a self-signed certificate with

     30: $    saws/CA.pl  -newcert  (using the passphrase of password)
     31: $    cat newkey.pem newcert.pem > sslclient.pem

     33:     and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of
     34:     silly but it was all I could figure out.

     36: */
     37: PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx)
     38: {
     39:     SSL_CTX        *ctx;
     40: #if defined(PETSC_USE_SSL_CERTIFICATE)
     41:     char           keyfile[PETSC_MAX_PATH_LEN];
     42:     PetscBool      exists;
     44: #endif

     47:     if (!bio_err){
     48:       SSL_library_init();
     49:       SSL_load_error_strings();
     50:       bio_err = BIO_new_fp(stderr,BIO_NOCLOSE);
     51:     }

     53:     /* Set up a SIGPIPE handler */
     54:     signal(SIGPIPE,sigpipe_handle);

     56:     ctx  = SSL_CTX_new(SSLv23_method());
     57:     SSL_CTX_set_mode(ctx,SSL_MODE_AUTO_RETRY);

     59: #if defined(PETSC_USE_SSL_CERTIFICATE)
     60:     /* Locate keyfile */
     61:     PetscStrcpy(keyfile,"sslclient.pem");
     62:     PetscTestFile(keyfile,'r',&exists);
     63:     if (!exists) {
     64:       PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);
     65:       PetscStrcat(keyfile,"/");
     66:       PetscStrcat(keyfile,"sslclient.pem");
     67:       PetscTestFile(keyfile,'r',&exists);
     68:       if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory");
     69:     }

     71:     /* Load our keys and certificates*/
     72:     if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file");

     74:     SSL_CTX_set_default_passwd_cb(ctx,password_cb);
     75:     if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file");
     76: #endif

     78:     *octx = ctx;
     79:     return(0);
     80: }

     84: PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx)
     85: {
     87:   SSL_CTX_free(ctx);
     88:   return(0);
     89: }

     93: PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest)
     94: {
     95:   char           *request=0;
     96:   char           contentlength[40],contenttype[80],*path,*host;
     97:   size_t         request_len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0;
     99:   PetscBool      flg;

    102:   PetscStrallocpy(url,&host);
    103:   PetscStrchr(host,'/',&path);
    104:   if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url);
    105:   *path = 0;
    106:   PetscStrlen(host,&hostlen);

    108:   PetscStrchr(url,'/',&path);
    109:   PetscStrlen(path,&pathlen);

    111:   if (header) {
    112:     PetscStrendswith(header,"\r\n",&flg);
    113:     if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n");
    114:   }

    116:   PetscStrlen(type,&typelen);
    117:   if (ctype) {
    118:     PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);
    119:     PetscStrlen(contenttype,&contenttypelen);
    120:   }
    121:   PetscStrlen(header,&headlen);
    122:   PetscStrlen(body,&bodylen);
    123:   PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);
    124:   PetscStrlen(contentlength,&contentlen);

    126:   /* Now construct our HTTP request */
    127:   request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1;
    128:   PetscMalloc1(request_len,&request);
    129:   PetscStrcpy(request,type);
    130:   PetscStrcat(request," ");
    131:   PetscStrcat(request,path);
    132:   PetscStrcat(request," HTTP/1.1\r\nHost: ");
    133:   PetscStrcat(request,host);
    134:   PetscFree(host);
    135:   PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");
    136:   PetscStrcat(request,header);
    137:   if (ctype) {
    138:     PetscStrcat(request,contenttype);
    139:   }
    140:   PetscStrcat(request,contentlength);
    141:   PetscStrcat(request,body);
    142:   PetscStrlen(request,&request_len);
    143:   PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);

    145:   *outrequest = request;
    146:   return(0);
    147: }

    152: /*
    153:      PetscHTTPSRequest - Send a request to an HTTPS server

    155:    Input Parameters:
    156: +   type - either "POST" or "GET"
    157: .   url -  URL of request host/path
    158: .   header - additional header information, may be NULL
    159: .   ctype - data type of body, for example application/json
    160: .   body - data to send to server
    161: .   ssl - obtained with PetscHTTPSConnect()
    162: -   buffsize - size of buffer

    164:    Output Parameter:
    165: .   buff - everything returned from server
    166:  */
    167: PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize)
    168: {
    169:   char           *request;
    170:   int            r;
    171:   size_t         request_len,len;
    173:   PetscBool      foundbody = PETSC_FALSE;

    176:   PetscHTTPBuildRequest(type,url,header,ctype,body,&request);
    177:   PetscStrlen(request,&request_len);

    179:   r = SSL_write(ssl,request,(int)request_len);
    180:   switch (SSL_get_error(ssl,r)){
    181:     case SSL_ERROR_NONE:
    182:       if (request_len != (size_t)r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket");
    183:       break;
    184:     default:
    185:       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem");
    186:   }

    188:   /* Now read the server's response, globus sends it in two chunks hence must read a second time if needed */
    189:   PetscMemzero(buff,buffsize);
    190:   len       = 0;
    191:   foundbody = PETSC_FALSE;
    192:   do {
    193:     char   *clen;
    194:     int    cl;
    195:     size_t nlen;

    197:     r = SSL_read(ssl,buff+len,(int)buffsize);
    198:     len += r;
    199:     switch (SSL_get_error(ssl,r)){
    200:     case SSL_ERROR_NONE:
    201:       break;
    202:     case SSL_ERROR_ZERO_RETURN:
    203:       foundbody = PETSC_TRUE;
    204:       SSL_shutdown(ssl);
    205:       break;
    206:     case SSL_ERROR_SYSCALL:
    207:       foundbody = PETSC_TRUE;
    208:       break;
    209:     default:
    210:       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem");
    211:     }

    213:     PetscStrstr(buff,"Content-Length: ",&clen);
    214:     if (clen) {
    215:       clen += 15;
    216:       sscanf(clen,"%d",&cl);
    217:       if (!cl) foundbody = PETSC_TRUE;
    218:       else {
    219:         PetscStrstr(buff,"\r\n\r\n",&clen);
    220:         if (clen) {
    221:           PetscStrlen(clen,&nlen);
    222:           if (nlen-4 == (size_t) cl) foundbody = PETSC_TRUE;
    223:         }
    224:       }
    225:     } else {
    226:       /* if no content length than must leave because you don't know if you can read again */
    227:       foundbody = PETSC_TRUE;
    228:     }
    229:   } while (!foundbody);
    230:   PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);

    232:   SSL_free(ssl);
    233:   PetscFree(request);
    234:   return(0);
    235: }

    239: /*
    240:      PetscHTTPRequest - Send a request to an HTTP server

    242:    Input Parameters:
    243: +   type - either "POST" or "GET"
    244: .   url -  URL of request host/path
    245: .   header - additional header information, may be NULL
    246: .   ctype - data type of body, for example application/json
    247: .   body - data to send to server
    248: .   sock - obtained with PetscOpenSocket()
    249: -   buffsize - size of buffer

    251:    Output Parameter:
    252: .   buff - everything returned from server
    253:  */
    254: PetscErrorCode PetscHTTPRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],int sock,char buff[],size_t buffsize)
    255: {
    256:   char           *request;
    257:   size_t         request_len;

    261:   PetscHTTPBuildRequest(type,url,header,ctype,body,&request);
    262:   PetscStrlen(request,&request_len);

    264:   PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);
    265:   PetscFree(request);
    266:   PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR);
    267:   buff[buffsize-1] = 0;
    268:   PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);
    269:   return(0);
    270: }

    274: PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl)
    275: {
    276:   BIO            *sbio;

    280:   /* Connect the TCP socket*/
    281:   PetscOpenSocket(host,port,sock);

    283:   /* Connect the SSL socket */
    284:   *ssl = SSL_new(ctx);
    285:   sbio = BIO_new_socket(*sock,BIO_NOCLOSE);
    286:   SSL_set_bio(*ssl,sbio,sbio);
    287:   if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error");
    288:   return(0);
    289: }

    293: /*
    294:      Given a JSON response containing the substring with "key" : "value"  where there may or not be spaces around the : returns the value.
    295: */
    296: PetscErrorCode PetscPullJSONValue(const char buff[],const char key[],char value[],size_t valuelen,PetscBool *found)
    297: {
    299:   char           *v,*w;
    300:   char           work[256];
    301:   size_t         len;

    304:   PetscStrcpy(work,"\"");
    305:   PetscStrncat(work,key,250);
    306:   PetscStrcat(work,"\":");
    307:   PetscStrstr(buff,work,&v);
    308:   PetscStrlen(work,&len);
    309:   if (v) {
    310:     v += len;
    311:   } else {
    312:     work[len++-1] = 0;
    313:     PetscStrcat(work," :");
    314:     PetscStrstr(buff,work,&v);
    315:     if (!v) {
    316:       *found = PETSC_FALSE;
    317:       return(0);
    318:     }
    319:     v += len;
    320:   }
    321:   PetscStrchr(v,'\"',&v);
    322:   if (!v) {
    323:     *found = PETSC_FALSE;
    324:     return(0);
    325:   }
    326:   PetscStrchr(v+1,'\"',&w);
    327:   if (!w) {
    328:     *found = PETSC_FALSE;
    329:     return(0);
    330:   }
    331:   *found = PETSC_TRUE;
    332:   PetscStrncpy(value,v+1,PetscMin((size_t)(w-v),valuelen));
    333:   return(0);
    334: }

    336: #include <ctype.h>

    340: /*
    341:      Pushs a "key" : "value" pair onto a string

    343:      Ignores lengths so can cause buffer overflow
    344: */
    345: PetscErrorCode PetscPushJSONValue(char buff[],const char key[],const char value[],size_t bufflen)
    346: {
    348:   size_t         len;
    349:   PetscBool      special;

    352:   PetscStrcmp(value,"null",&special);
    353:   if (!special) {
    354:     PetscStrcmp(value,"true",&special);
    355:   }
    356:   if (!special) {
    357:     PetscStrcmp(value,"false",&special);
    358:   }
    359:   if (!special) {
    360:     PetscInt i;

    362:     PetscStrlen(value,&len);
    363:     special = PETSC_TRUE;
    364:     for (i=0; i<(int)len; i++) {
    365:       if (!isdigit(value[i])) {
    366:         special = PETSC_FALSE;
    367:         break;
    368:       }
    369:     }
    370:   }

    372:   PetscStrcat(buff,"\"");
    373:   PetscStrcat(buff,key);
    374:   PetscStrcat(buff,"\":");
    375:   if (!special) {
    376:     PetscStrcat(buff,"\"");
    377:   }
    378:   PetscStrcat(buff,value);
    379:   if (!special) {
    380:     PetscStrcat(buff,"\"");
    381:   }
    382:   return(0);
    383: }