text: /*********************************************************************
  *    Copyright 2018, UCAR/Unidata
  *    See netcdf/COPYRIGHT file for copying and redistribution conditions.
  * ********************************************************************/
  
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   * Copyright by The HDF Group.                                               *
   * Copyright by the Board of Trustees of the University of Illinois.         *
   * All rights reserved.                                                      *
   *                                                                           *
   * This file is part of HDF5.  The full HDF5 copyright notice, including     *
   * terms governing use, modification, and redistribution, is contained in    *
   * the COPYING file, which can be found at the root of the source code       *
   * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
   * If you do not have access to either file, you may request a copy from     *
   * help@hdfgroup.org.                                                        *
   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  
  /* Programmer:  Dennis Heimbigner dmh@ucar.edu
   *
   * Purpose:  Access remote datasets using byte range requests.
   * Derived from the HDF5 H5FDstdio.c file.
   *
   * NOTE:    This driver is not as well tested as the standard SEC2 driver
   *          and is not intended for production use!
   */
  
  #include "config.h"
  
  #include <assert.h>
  #include <errno.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <sys/stat.h>
  
  #include <hdf5.h>
  #include <curl/curl.h>
  
  #ifdef H5_HAVE_FLOCK
  /* Needed for lock type definitions (e.g., LOCK_EX) */
  #include <sys/file.h>
  #endif /* H5_HAVE_FLOCK */
  
  #ifdef H5_HAVE_UNISTD_H
  #include <unistd.h>
  #endif
  
  /*
  Define a simple #ifdef test for the version of H5FD_class_t we are using 
  */
  #if H5_VERS_MAJOR == 1
  #if H5_VERS_MINOR < 10
  #define H5FDCLASS1 1
  #endif
  #else
  #error "Cannot determine version of H5FD_class_t"
  #endif
  
  #ifdef H5_HAVE_WIN32_API
  /* The following two defines must be before any windows headers are included */
  #define WIN32_LEAN_AND_MEAN    /* Exclude rarely-used stuff from Windows headers */
  #define NOGDI                  /* Exclude Graphic Display Interface macros */
  
  #include <windows.h>
  #include <io.h>
  
  #endif /* H5_HAVE_WIN32_API */
  
  #include "netcdf.h"
  #include "ncbytes.h"
  #include "nclist.h"
  #include "nchttp.h"
  
  #include "H5FDhttp.h"
  
  typedef off_t file_offset_t;
  
  /* The driver identification number, initialized at runtime */
  static hid_t H5FD_HTTP_g = 0;
  
  /* File operations */
  typedef enum {
      H5FD_HTTP_OP_UNKNOWN=0,
      H5FD_HTTP_OP_READ=1,
      H5FD_HTTP_OP_WRITE=2,
      H5FD_HTTP_OP_SEEK=3
  } H5FD_http_file_op;
  
  /* The description of a file belonging to this driver. The 'eoa' and 'eof'
   * determine the amount of hdf5 address space in use and the high-water mark
   * of the file (the current size of the underlying Unix file). The 'pos'
   * value is used to eliminate file position updates when they would be a
   * no-op. Unfortunately we've found systems that use separate file position
   * indicators for reading and writing so the lseek can only be eliminated if
   * the current operation is the same as the previous operation.  When opening
   * a file the 'eof' will be set to the current file size, 'eoa' will be set
   * to zero, 'pos' will be set to H5F_ADDR_UNDEF (as it is when an error
   * occurs), and 'op' will be set to H5F_OP_UNKNOWN.
   */
  typedef struct H5FD_http_t {
      H5FD_t      pub;            /* public stuff, must be first      */
      haddr_t     eoa;            /* end of allocated region          */
      haddr_t     eof;            /* end of file; current file size   */
      haddr_t     pos;            /* current file I/O position        */
      unsigned    write_access;   /* Flag to indicate the file was opened with write access */
      H5FD_http_file_op op;		/* last operation */
      NC_HTTP_STATE*  state;       /* Curl handle + extra */
      char*           url;        /* The URL (minus any fragment) for the dataset */ 
  } H5FD_http_t;
  
  
  /* These macros check for overflow of various quantities.  These macros
   * assume that file_offset_t is signed and haddr_t and size_t are unsigned.
   *
   * ADDR_OVERFLOW:  Checks whether a file address of type `haddr_t'
   *      is too large to be represented by the second argument
   *      of the file seek function.
   *
   * SIZE_OVERFLOW:  Checks whether a buffer size of type `hsize_t' is too
   *      large to be represented by the `size_t' type.
   *
   * REGION_OVERFLOW:  Checks whether an address and size pair describe data
   *      which can be addressed entirely by the second
   *      argument of the file seek function.
   */
  /* adding for windows NT filesystem support. */
  #define MAXADDR (((haddr_t)1<<(8*sizeof(file_offset_t)-1))-1)
  #define ADDR_OVERFLOW(A)  (HADDR_UNDEF==(A) || ((A) & ~(haddr_t)MAXADDR))
  #define SIZE_OVERFLOW(Z)  ((Z) & ~(hsize_t)MAXADDR)
  #define REGION_OVERFLOW(A,Z)  (ADDR_OVERFLOW(A) || SIZE_OVERFLOW(Z) || \
      HADDR_UNDEF==(A)+(Z) || (file_offset_t)((A)+(Z))<(file_offset_t)(A))
  
  /* Prototypes */
  static H5FD_t *H5FD_http_open(const char *name, unsigned flags,
                   hid_t fapl_id, haddr_t maxaddr);
  static herr_t H5FD_http_close(H5FD_t *lf);
  static int H5FD_http_cmp(const H5FD_t *_f1, const H5FD_t *_f2);
  static herr_t H5FD_http_query(const H5FD_t *_f1, unsigned long *flags);
  static haddr_t H5FD_http_alloc(H5FD_t *_file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size);
  static haddr_t H5FD_http_get_eoa(const H5FD_t *_file, H5FD_mem_t type);
  static herr_t H5FD_http_set_eoa(H5FD_t *_file, H5FD_mem_t type, haddr_t addr);
  static herr_t  H5FD_http_get_handle(H5FD_t *_file, hid_t fapl, void** file_handle);
  static herr_t H5FD_http_read(H5FD_t *lf, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
                  size_t size, void *buf);
  static herr_t H5FD_http_write(H5FD_t *lf, H5FD_mem_t type, hid_t fapl_id, haddr_t addr,
                  size_t size, const void *buf);
  
  /* The H5FD_class_t structure has different versions */
  #ifdef H5FDCLASS1
  static haddr_t H5FD_http_get_eof(const H5FD_t *_file);
  static herr_t H5FD_http_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing);
  static herr_t H5FD_http_lock(H5FD_t *_file, unsigned char* old, unsigned lock_type, hbool_t last);
  static herr_t H5FD_http_unlock(H5FD_t *file, unsigned char *oid, hbool_t last);
  #else
  static herr_t H5FD_http_term(void);
  static haddr_t H5FD_http_get_eof(const H5FD_t *_file, H5FD_mem_t type);
  static herr_t H5FD_http_flush(H5FD_t *_file, hid_t dxpl_id, hbool_t closing);
  static herr_t H5FD_http_lock(H5FD_t *_file, hbool_t rw);
  static herr_t H5FD_http_unlock(H5FD_t *_file);
  #endif
  
  /* Beware, not same as H5FD_HTTP_g */
  static const H5FD_class_t H5FD_http_g = {
      "http",                     /* name         */
      MAXADDR,                    /* maxaddr      */
      H5F_CLOSE_WEAK,             /* fc_degree    */
  #ifndef H5FDCLASS1
      H5FD_http_term,             /* terminate    */
  #endif
      NULL,                       /* sb_size      */
      NULL,                       /* sb_encode    */
      NULL,                       /* sb_decode    */
      0,                          /* fapl_size    */
      NULL,                       /* fapl_get     */
      NULL,                       /* fapl_copy    */
      NULL,                       /* fapl_free    */
      0,                          /* dxpl_size    */
      NULL,                       /* dxpl_copy    */
      NULL,                       /* dxpl_free    */
      H5FD_http_open,            /* open         */
      H5FD_http_close,           /* close        */
      H5FD_http_cmp,             /* cmp          */
      H5FD_http_query,           /* query        */
      NULL,                       /* get_type_map */
      H5FD_http_alloc,           /* alloc        */
      NULL,                       /* free         */
      H5FD_http_get_eoa,         /* get_eoa      */
      H5FD_http_set_eoa,         /* set_eoa      */
      H5FD_http_get_eof,         /* get_eof      */
      H5FD_http_get_handle,      /* get_handle   */
      H5FD_http_read,            /* read         */
      H5FD_http_write,           /* write        */
      H5FD_http_flush,           /* flush        */
      NULL, 		       /* truncate     */
      H5FD_http_lock,            /* lock         */
      H5FD_http_unlock,          /* unlock       */
      H5FD_FLMAP_DICHOTOMY       /* fl_map       */
  };
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_init
   *
   * Purpose:  Initialize this driver by registering the driver with the
   *    library.
   *
   * Return:  Success:  The driver ID for the driver.
   *
   *    Failure:  Negative.
   *
   * Programmer:  Robb Matzke
   *              Thursday, July 29, 1999
   *
   *-------------------------------------------------------------------------
   */
  EXTERNL hid_t
  H5FD_http_init(void)
  {
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      if (H5I_VFL!=H5Iget_type(H5FD_HTTP_g))
          H5FD_HTTP_g = H5FDregister(&H5FD_http_g);
      return H5FD_HTTP_g;
  } /* end H5FD_http_init() */
  
  
  /*---------------------------------------------------------------------------
   * Function:  H5FD_http_term
   *
   * Purpose:  Shut down the VFD
   *
   * Returns:     Non-negative on success or negative on failure
   *
   * Programmer:  Quincey Koziol
   *              Friday, Jan 30, 2004
   *
   *---------------------------------------------------------------------------
   */
  #ifndef H5FDCLASS1
  static herr_t
  H5FD_http_term(void)
  {
      /* Reset VFL ID */
      H5FD_HTTP_g = 0;
  
      return 0;
  } /* end H5FD_http_term() */
  #endif
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5Pset_fapl_http
   *
   * Purpose:  Modify the file access property list to use the H5FD_HTTP
   *    driver defined in this source file.  There are no driver
   *    specific properties.
   *
   * Return:  Non-negative on success/Negative on failure
   *
   * Programmer:  Robb Matzke
   *    Thursday, February 19, 1998
   *
   *-------------------------------------------------------------------------
   */
  EXTERNL herr_t
  H5Pset_fapl_http(hid_t fapl_id)
  {
      static const char *func = "H5FDset_fapl_http";  /*for error reporting*/
  
      /*NO TRACE*/
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      if(0 == H5Pisa_class(fapl_id, H5P_FILE_ACCESS))
          H5Epush_ret(func, H5E_ERR_CLS, H5E_PLIST, H5E_BADTYPE, "not a file access property list", -1);
  
      return H5Pset_driver(fapl_id, H5FD_HTTP, NULL);
  } /* end H5Pset_fapl_http() */
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_open
   *
   * Purpose:  Opens a remote Object as an HDF5 file.
   *
   * Errors:
   *  IO  CANTOPENFILE    File doesn't exist and CREAT wasn't
   *                      specified.
   *
   * Return:
   *      Success:    A pointer to a new file data structure. The
   *                  public fields will be initialized by the
   *                  caller, which is always H5FD_open().
   *
   *      Failure:    NULL
   *
   * Programmer:  Dennis Heimbigner
   *
   *-------------------------------------------------------------------------
   */
  static H5FD_t *
  H5FD_http_open( const char *name, unsigned flags, hid_t /*UNUSED*/ fapl_id,
      haddr_t maxaddr)
  {
      unsigned            write_access = 0;           /* File opened with write access? */
      H5FD_http_t *file = NULL;
      static const char   *func = "H5FD_http_open";  /* Function Name for error reporting */
      long long len = -1;
      int ncstat = NC_NOERR;
      NC_HTTP_STATE* state = NULL;
  
      /* Sanity check on file offsets */
      assert(sizeof(file_offset_t) >= sizeof(size_t));
  
      /* Quiet compiler */
      fapl_id = fapl_id;
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      /* Check arguments */
      if (!name || !*name)
          H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADVALUE, "invalid URL", NULL);
      if (0 == maxaddr || HADDR_UNDEF == maxaddr)
          H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_BADRANGE, "bogus maxaddr", NULL);
      if (ADDR_OVERFLOW(maxaddr))
          H5Epush_ret(func, H5E_ERR_CLS, H5E_ARGS, H5E_OVERFLOW, "maxaddr too large", NULL);
  
      /* Always read-only */
      write_access = 0;
  
      /* Open file in read-only mode, to check for existence  and get length */
      if((ncstat = nc_http_open(name,&state,&len))) {
          H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_CANTOPENFILE, "cannot access object", NULL);
      }
  
      /* Build the return value */
      if(NULL == (file = (H5FD_http_t *)H5allocate_memory(sizeof(H5FD_http_t),0))) {
  	nc_http_close(state);
          H5Epush_ret(func, H5E_ERR_CLS, H5E_RESOURCE, H5E_NOSPACE, "memory allocation failed", NULL);
      } /* end if */
      memset(file,0,sizeof(H5FD_http_t));
  
      file->op = H5FD_HTTP_OP_SEEK;
      file->pos = HADDR_UNDEF;
      file->write_access = write_access;    /* Note the write_access for later */
      file->eof = (haddr_t)len;
      file->state = state; state = NULL;
      file->url = H5allocate_memory(strlen(name+1),0);
      if(file->url == NULL) {
  	nc_http_close(state);
          H5Epush_ret(func, H5E_ERR_CLS, H5E_RESOURCE, H5E_NOSPACE, "memory allocation failed", NULL);
      }
      memcpy(file->url,name,strlen(name)+1);
  
      return((H5FD_t*)file);
  } /* end H5FD_HTTP_OPen() */
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5F_http_close
   *
   * Purpose:  Closes a file.
   *
   * Errors:
   *    IO    CLOSEERROR  Fclose failed.
   *
   * Return:  Non-negative on success/Negative on failure
   *
   * Programmer:  Dennis Heimbigner
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5FD_http_close(H5FD_t *_file)
  {
      H5FD_http_t  *file = (H5FD_http_t*)_file;
  #if 0
      static const char *func = "H5FD_http_close";  /* Function Name for error reporting */
  #endif
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      /* Close the underlying curl handle*/
      if(file->state) nc_http_close(file->state);
      if(file->url) H5free_memory(file->url);
  
      H5free_memory(file);
  
      return 0;
  } /* end H5FD_http_close() */
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_cmp
   *
   * Purpose:  Compares two files belonging to this driver using an
   *    arbitrary (but consistent) ordering.
   *
   * Return:
   *      Success:    A value like strcmp()
   *
   *      Failure:    never fails (arguments were checked by the caller).
   *
   * Programmer:  Robb Matzke
   *              Thursday, July 29, 1999
   *
   *-------------------------------------------------------------------------
   */
  static int
  H5FD_http_cmp(const H5FD_t *_f1, const H5FD_t *_f2)
  {
      const H5FD_http_t  *f1 = (const H5FD_http_t*)_f1;
      const H5FD_http_t  *f2 = (const H5FD_http_t*)_f2;
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      if(strcmp(f1->url,f2->url) < 0) return -1;
      if(strcmp(f1->url,f2->url) > 0) return 1;
      return 0;
  } /* H5FD_http_cmp() */
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_query
   *
   * Purpose:  Set the flags that this VFL driver is capable of supporting.
   *              (listed in H5FDpublic.h)
   *
   * Return:  Success:  non-negative
   *
   *    Failure:  negative
   *
   * Programmer:  Quincey Koziol
   *              Friday, August 25, 2000
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5FD_http_query(const H5FD_t *_f, unsigned long /*OUT*/ *flags)
  {
      /* Quiet the compiler */
      _f=_f;
  
      /* Set the VFL feature flags that this driver supports.
       *
       * Note that this VFD does not support SWMR due to the unpredictable
       * nature of the buffering layer.
       */
      if(flags) {
          *flags = 0;
          *flags |= H5FD_FEAT_AGGREGATE_METADATA;     /* OK to aggregate metadata allocations                             */
          *flags |= H5FD_FEAT_ACCUMULATE_METADATA;    /* OK to accumulate metadata for faster writes                      */
          *flags |= H5FD_FEAT_DATA_SIEVE;             /* OK to perform data sieving for faster raw data reads & writes    */
          *flags |= H5FD_FEAT_AGGREGATE_SMALLDATA;    /* OK to aggregate "small" raw data allocations                     */
  #ifndef H5FDCLASS1
          *flags |= H5FD_FEAT_DEFAULT_VFD_COMPATIBLE; /* VFD creates a file which can be opened with the default VFD      */
  #endif
      }
  
      return 0;
  } /* end H5FD_http_query() */
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_alloc
   *
   * Purpose:     Allocates file memory. If fseeko isn't available, makes
   *              sure the file size isn't bigger than 2GB because the
   *              parameter OFFSET of fseek is of the type LONG INT, limiting
   *              the file size to 2GB.
   *
   * Return:
   *      Success:    Address of new memory
   *
   *      Failure:    HADDR_UNDEF
   *
   * Programmer:  Raymond Lu
   *              30 March 2007
   *
   *-------------------------------------------------------------------------
   */
  static haddr_t
  H5FD_http_alloc(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxpl_id, hsize_t size)
  {
      H5FD_http_t    *file = (H5FD_http_t*)_file;
      haddr_t         addr;
  
      /* Quiet compiler */
      type = type;
      dxpl_id = dxpl_id;
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      /* Compute the address for the block to allocate */
      addr = file->eoa;
  
      file->eoa = addr + size;
  
      return addr;
  } /* end H5FD_http_alloc() */
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_get_eoa
   *
   * Purpose:  Gets the end-of-address marker for the file. The EOA marker
   *           is the first address past the last byte allocated in the
   *           format address space.
   *
   * Return:  Success:  The end-of-address marker.
   *
   *    Failure:  HADDR_UNDEF
   *
   * Programmer:  Robb Matzke
   *              Monday, August  2, 1999
   *
   *-------------------------------------------------------------------------
   */
  static haddr_t
  H5FD_http_get_eoa(const H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type)
  {
      const H5FD_http_t *file = (const H5FD_http_t *)_file;
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      /* Quiet compiler */
      type = type;
  
      return file->eoa;
  } /* end H5FD_http_get_eoa() */
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_set_eoa
   *
   * Purpose:  Set the end-of-address marker for the file. This function is
   *    called shortly after an existing HDF5 file is opened in order
   *    to tell the driver where the end of the HDF5 data is located.
   *
   * Return:  Success:  0
   *
   *    Failure:  Does not fail
   *
   * Programmer:  Robb Matzke
   *              Thursday, July 29, 1999
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5FD_http_set_eoa(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, haddr_t addr)
  {
      H5FD_http_t  *file = (H5FD_http_t*)_file;
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      /* Quiet the compiler */
      type = type;
  
      file->eoa = addr;
  
      return 0;
  }
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_get_eof
   *
   * Purpose:  Returns the end-of-file marker, which is the greater of
   *    either the Unix end-of-file or the HDF5 end-of-address
   *    markers.
   *
   * Return:  Success:  End of file address, the first address past
   *        the end of the "file", either the Unix file
   *        or the HDF5 file.
   *
   *    Failure:  HADDR_UNDEF
   *
   * Programmer:  Robb Matzke
   *              Thursday, July 29, 1999
   *
   *-------------------------------------------------------------------------
   */
  
  static haddr_t
  #ifdef H5FDCLASS1
  H5FD_http_get_eof(const H5FD_t *_file)
  #else
  H5FD_http_get_eof(const H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type)
  #endif
  {
      const H5FD_http_t  *file = (const H5FD_http_t *)_file;
  
  #ifndef H5FDCLASS1
      /* Quiet the compiler */
      type = type;
  #endif
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      return(file->eof);
  } /* end H5FD_http_get_eof() */
  
  
  /*-------------------------------------------------------------------------
   * Function:       H5FD_http_get_handle
   *
   * Purpose:        Returns the file handle of file driver.
   *
   * Returns:        Non-negative if succeed or negative if fails.
   *
   * Programmer:     Raymond Lu
   *                 Sept. 16, 2002
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5FD_http_get_handle(H5FD_t *_file, hid_t /*UNUSED*/ fapl, void **file_handle)
  {
      H5FD_http_t       *file = (H5FD_http_t *)_file;
      static const char  *func = "H5FD_http_get_handle";  /* Function Name for error reporting */
  
      /* Quiet the compiler */
      fapl = fapl;
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      *file_handle = file->state;
      if(*file_handle == NULL)
          H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "get handle failed", -1);
  
      return 0;
  } /* end H5FD_http_get_handle() */
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_read
   *
   * Purpose:  Reads SIZE bytes beginning at address ADDR in file LF and
   *    places them in buffer BUF.  Reading past the logical or
   *    physical end of file returns zeros instead of failing.
   *
   * Errors:
   *    IO    READERROR  fread failed.
   *    IO    SEEKERROR  fseek failed.
   *
   * Return:  Non-negative on success/Negative on failure
   *
   * Programmer:  Robb Matzke
   *    Wednesday, October 22, 1997
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5FD_http_read(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxpl_id,
      haddr_t addr, size_t size, void /*OUT*/ *buf)
  {
      H5FD_http_t    *file = (H5FD_http_t*)_file;
      static const char *func = "H5FD_http_read";  /* Function Name for error reporting */
      int ncstat = NC_NOERR;
  
      /* Quiet the compiler */
      type = type;
      dxpl_id = dxpl_id;
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      /* Check for overflow */
      if (HADDR_UNDEF==addr)
          H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1);
      if (REGION_OVERFLOW(addr, size))
          H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_OVERFLOW, "file address overflowed", -1);
  
      /* Check easy cases */
      if (0 == size)
          return 0;
      if ((haddr_t)addr >= file->eof) {
          memset(buf, 0, size);
          return 0;
      }
  
      /* Seek to the correct file position. */
      if (!(file->op == H5FD_HTTP_OP_READ || file->op == H5FD_HTTP_OP_SEEK) ||
              file->pos != addr) {
  #if 0
          if (file_fseek(file->fp, (file_offset_t)addr, SEEK_SET) < 0) {
              file->op = H5FD_HTTP_OP_UNKNOWN;
              file->pos = HADDR_UNDEF;
              H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_SEEKERROR, "fseek failed", -1);
          }
  #endif
          file->pos = addr;
      }
  
      /* Read zeros past the logical end of file (physical is handled below) */
      if (addr + size > file->eof) {
          size_t nbytes = (size_t) (addr + size - file->eof);
          memset((unsigned char *)buf + size - nbytes, 0, nbytes);
          size -= nbytes;
      }
  
      {
  	NCbytes* bbuf = ncbytesnew();
          if((ncstat = nc_http_read(file->state,file->url,addr,size,bbuf))) {
              file->op = H5FD_HTTP_OP_UNKNOWN;
              file->pos = HADDR_UNDEF;
  	    ncbytesfree(bbuf); bbuf = NULL;
              H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_READERROR, "HTTP byte-range read failed", -1);
          } /* end if */
  
  	/* Check that proper number of bytes was read */
  	if(ncbyteslength(bbuf) != size) {
  	    ncbytesfree(bbuf); bbuf = NULL;
              H5Epush_ret(func, H5E_ERR_CLS, H5E_IO, H5E_READERROR, "HTTP byte-range read mismatch ", -1);
  	}	
  
  	/* Extract the data from buf */
  	memcpy(buf,ncbytescontents(bbuf),size);	        
  	ncbytesfree(bbuf);
      }
  
      /* Update the file position data. */
      file->op = H5FD_HTTP_OP_READ;
      file->pos = addr;
  
      return 0;
  }
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_write
   *
   * Purpose:  Writes SIZE bytes from the beginning of BUF into file LF at
   *    file address ADDR.
   *
   * Errors:
   *    IO    SEEKERROR   fseek failed.
   *    IO    WRITEERROR  fwrite failed.
   *
   * Return:  Non-negative on success/Negative on failure
   *
   * Programmer:  Dennis Heimbigner
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  H5FD_http_write(H5FD_t *_file, H5FD_mem_t /*UNUSED*/ type, hid_t /*UNUSED*/ dxpl_id,
      haddr_t addr, size_t size, const void *buf)
  {
      static const char *func = "H5FD_http_write";  /* Function Name for error reporting */
  
      /* Quiet the compiler */
      dxpl_id = dxpl_id;
      type = type;
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      /* Always Fails */
      H5Epush_ret (func, H5E_ERR_CLS, H5E_IO, H5E_WRITEERROR, "file is read-only", -1);
  
      return 0;
  }
  
  
  /*-------------------------------------------------------------------------
   * Function:  H5FD_http_flush
   *
   * Purpose:  Makes sure that all data is on disk.
   *
   * Errors:
   *    IO    SEEKERROR     fseek failed.
   *    IO    WRITEERROR    fflush or fwrite failed.
   *
   * Return:  Non-negative on success/Negative on failure
   *
   * Programmer:  Robb Matzke
   *    Wednesday, October 22, 1997
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  #ifdef H5FDCLASS1
  H5FD_http_flush(H5FD_t *_file, hid_t dxpl_id, unsigned closing)
  #else
  H5FD_http_flush(H5FD_t *_file, hid_t /*UNUSED*/ dxpl_id, hbool_t closing)
  #endif
  {
  
  #ifndef H5FDCLASS1
      /* Quiet the compiler */
      dxpl_id = dxpl_id;
  #endif
  
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      return 0;
  } /* end H5FD_http_flush() */
  
  
  /*-------------------------------------------------------------------------
   * Function:    H5FD_http_lock
   *
   * Purpose:     Lock a file via flock
   *              NOTE: This function is a no-op if flock() is not present.
   *
   * Errors:
   *    IO    FCNTL    flock failed.
   *
   * Return:      Non-negative on success/Negative on failure
   *
   * Programmer:  Vailin Choi; March 2015
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  #ifdef H5FDCLASS1
  H5FD_http_lock(H5FD_t *_file, unsigned char* old, unsigned lock_type, hbool_t last)
  #else
  H5FD_http_lock(H5FD_t *_file, hbool_t rw)
  #endif
  {
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
  #ifdef H5FDCLASS1
      /* Quiet the compiler */
      lock_type = lock_type;
      last = last;
  #else
      rw = rw;
  #endif
  
      return 0;
  } /* end H5FD_http_lock() */
  
  /*-------------------------------------------------------------------------
   * Function:    H5F_http_unlock
   *
   * Purpose:     Unlock a file via flock
   *              NOTE: This function is a no-op if flock() is not present.
   *
   * Errors:
   *    IO    FCNTL    flock failed.
   *
   * Return:      Non-negative on success/Negative on failure
   *
   * Programmer:  Vailin Choi; March 2015
   *
   *-------------------------------------------------------------------------
   */
  static herr_t
  #ifdef H5FDCLASS1
  H5FD_http_unlock(H5FD_t *file, /*UNUSED*/unsigned char *oid, /*UNUSED*/ hbool_t last)
  #else
  H5FD_http_unlock(H5FD_t *_file)
  #endif
  {
      /* Clear the error stack */
      H5Eclear2(H5E_DEFAULT);
  
      /* Quiet the compiler */
  #ifdef H5FDCLASS1
      oid = oid;
      last = last;
  #endif
  
      return 0;
  } /* end H5FD_http_unlock() */
  
  
  #ifdef _H5private_H
  /*
   * This is not related to the functionality of the driver code.
   * It is added here to trigger warning if HDF5 private definitions are included
   * by mistake.  The code should use only HDF5 public API and definitions.
   */
  #error "Do not use HDF5 private definitions"
  #endif
  