// Get retrieves the given edition ID using an HTTP client, writes it to the
// Writer, and validates the hash before committing.
Get retrieves the given edition ID using an HTTP client, writes it to the
Writer, and validates the hash before committing.
// Get retrieves the given edition ID using an HTTP client writes it to the // Writer and validates the hash before committing .
func (reader *HTTPDatabaseReader) Get(destination Writer, editionID string) error {
	defer func() {
		if err := destination.Close(); err != nil {
			log.Println(err)
		}
	}()
	updateURL := fmt.Sprintf(
		"%s/geoip/databases/%s/update?db_md5=%s",
		reader.url,
		url.PathEscape(editionID),
		url.QueryEscape(destination.GetHash()),
	)
	var modified bool
	tempFile, err := ioutil.TempFile("", "geoipupdate")
	if err != nil {
		return errors.Wrap(err, "error opening temporary file")
	}
	defer func() {
		if err := tempFile.Close(); err != nil {
			log.Printf("error closing temporary file: %s", err)
		}
		if err := os.Remove(tempFile.Name()); err != nil {
			log.Printf("error removing temporary file: %s", err)
		}
	}()
	var newMD5 string
	var modificationTime time.Time
	err = internal.RetryWithBackoff(
		func() error {
			if reader.verbose {
				log.Printf("Performing update request to %s", updateURL)
			}
			newMD5, modificationTime, modified, err = reader.download(
				updateURL,
				editionID,
				tempFile,
			)
			return err
		},
		reader.retryFor,
	)
	if err != nil {
		return err
	}
	if !modified {
		return nil
	}
	if _, err := tempFile.Seek(0, 0); err != nil {
		return errors.Wrap(err, "error seeking")
	}
	if _, err = io.Copy(destination, tempFile); err != nil {
		return errors.Wrap(err, "error writing response")
	}
	if err := destination.ValidHash(newMD5); err != nil {
		return err
	}
	if err := destination.Commit(); err != nil {
		return errors.Wrap(err, "encountered an issue committing database update")
	}
	if reader.preserveFileTimes {
		err = destination.SetFileModificationTime(modificationTime)
		if err != nil {
			return errors.Wrap(err, "unable to set modification time")
		}
	}
	return nil
}
func ( reader * HTTPDatabaseReader ) Get ( destination Writer , editionID string ) error { defer func ( ) { if err := destination . Close ( ) ; err != nil { log . Println ( err ) } } ( ) updateURL := fmt . Sprintf ( " " , reader . url , url . PathEscape ( editionID ) , url . QueryEscape ( destination . GetHash ( ) ) , ) var modified bool tempFile , err := ioutil . TempFile ( " " , " " ) if err != nil { return errors . Wrap ( err , " " ) } defer func ( ) { if err := tempFile . Close ( ) ; err != nil { log . Printf ( " " , err ) } if err := os . Remove ( tempFile . Name ( ) ) ; err != nil { log . Printf ( " " , err ) } } ( ) var newMD5 string var modificationTime time . Time err = internal . RetryWithBackoff ( func ( ) error { if reader . verbose { log . Printf ( " " , updateURL ) } newMD5 , modificationTime , modified , err = reader . download ( updateURL , editionID , tempFile , ) return err } , reader . retryFor , ) if err != nil { return err } if ! modified { return nil } if _ , err := tempFile . Seek ( 0 , 0 ) ; err != nil { return errors . Wrap ( err , " " ) } if _ , err = io . Copy ( destination , tempFile ) ; err != nil { return errors . Wrap ( err , " " ) } if err := destination . ValidHash ( newMD5 ) ; err != nil { return err } if err := destination . Commit ( ) ; err != nil { return errors . Wrap ( err , " " ) } if reader . preserveFileTimes { err = destination . SetFileModificationTime ( modificationTime ) if err != nil { return errors . Wrap ( err , " " ) } } return nil }
Get retrieves the given edition ID using an HTTP client, writes it to the
Writer, and validates the hash before committing.
Get retrieves the given edition ID using an HTTP client writes it to the Writer and validates the hash before committing .
// It'd be nice to not use a temporary file here. However the Writer API does // not currently support multiple attempts to download the file (it assumes // we'll begin writing once). Using a temporary file here should be a less // disruptive alternative to changing the API. If we change that API in the // future, adding something like Reset() may be desirable. //nolint: gosec // see https://github.com/securego/gosec/issues/714