mirror of
https://github.com/lukaszraczylo/go-simple-graphql.git
synced 2026-10-19 01:27:43 +00:00
fixup! fixup! fixup! fixup! Library improvements.
This commit is contained in:
+40
-26
@@ -29,7 +29,7 @@ var (
|
|||||||
MaxIdleConns: 100,
|
MaxIdleConns: 100,
|
||||||
MaxIdleConnsPerHost: 100,
|
MaxIdleConnsPerHost: 100,
|
||||||
IdleConnTimeout: 90 * time.Second,
|
IdleConnTimeout: 90 * time.Second,
|
||||||
DisableCompression: true, // Disable automatic compression to handle gzip manually
|
DisableCompression: false, // Enable automatic compression for consistent handling
|
||||||
ForceAttemptHTTP2: true,
|
ForceAttemptHTTP2: true,
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // Skip TLS verification for test environments
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // Skip TLS verification for test environments
|
||||||
}
|
}
|
||||||
@@ -168,36 +168,35 @@ func (qe *QueryExecutor) executeQuery() ([]byte, error) {
|
|||||||
detectionMethod = "gzip_magic_bytes"
|
detectionMethod = "gzip_magic_bytes"
|
||||||
gzipReader, err := gzip.NewReader(bytes.NewReader(rawData))
|
gzipReader, err := gzip.NewReader(bytes.NewReader(rawData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
qe.Logger.Warning(&libpack_logger.LogMessage{
|
qe.Logger.Error(&libpack_logger.LogMessage{
|
||||||
Message: "Gzip magic bytes detected but failed to create gzip reader, falling back to uncompressed parsing",
|
Message: "Gzip magic bytes detected but failed to create gzip reader",
|
||||||
Pairs: map[string]interface{}{
|
Pairs: map[string]interface{}{
|
||||||
"gzip_error": err.Error(),
|
"gzip_reader_error": err.Error(),
|
||||||
"content_encoding_header": encoding,
|
"content_encoding_header": encoding,
|
||||||
"detection_method": detectionMethod,
|
"detection_method": detectionMethod,
|
||||||
|
"raw_size": len(rawData),
|
||||||
|
"first_two_bytes": fmt.Sprintf("0x%02x 0x%02x", rawData[0], rawData[1]),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
// Fallback: treat raw data as uncompressed
|
return fmt.Errorf("gzip reader creation failed: data has gzip magic bytes but gzip.NewReader error: %w", err)
|
||||||
finalData = rawData
|
|
||||||
detectionMethod = "fallback_to_plain"
|
|
||||||
} else {
|
} else {
|
||||||
// Successfully created gzip reader, now try to decompress
|
// Successfully created gzip reader, now try to decompress
|
||||||
defer gzipReader.Close()
|
defer gzipReader.Close()
|
||||||
|
|
||||||
_, copyErr := io.Copy(respBuf, gzipReader)
|
_, copyErr := io.Copy(respBuf, gzipReader)
|
||||||
if copyErr != nil {
|
if copyErr != nil {
|
||||||
// Gzip decompression failed, try fallback
|
// Gzip decompression failed - this is an error condition, not a fallback scenario
|
||||||
qe.Logger.Warning(&libpack_logger.LogMessage{
|
qe.Logger.Error(&libpack_logger.LogMessage{
|
||||||
Message: "Gzip magic bytes detected but decompression failed, falling back to uncompressed parsing",
|
Message: "Gzip magic bytes detected but decompression failed",
|
||||||
Pairs: map[string]interface{}{
|
Pairs: map[string]interface{}{
|
||||||
"copy_error": copyErr,
|
"gzip_decompress_error": copyErr.Error(),
|
||||||
"raw_size": len(rawData),
|
"raw_size": len(rawData),
|
||||||
"content_encoding_header": encoding,
|
"content_encoding_header": encoding,
|
||||||
"detection_method": detectionMethod,
|
"detection_method": detectionMethod,
|
||||||
|
"first_two_bytes": fmt.Sprintf("0x%02x 0x%02x", rawData[0], rawData[1]),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
// Fallback: treat raw data as uncompressed
|
return fmt.Errorf("gzip decompression failed: data has gzip magic bytes but decompression error: %w", copyErr)
|
||||||
finalData = rawData
|
|
||||||
detectionMethod = "fallback_to_plain"
|
|
||||||
} else {
|
} else {
|
||||||
// Successful decompression
|
// Successful decompression
|
||||||
finalData = respBuf.Bytes()
|
finalData = respBuf.Bytes()
|
||||||
@@ -213,18 +212,33 @@ func (qe *QueryExecutor) executeQuery() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if encoding == "gzip" {
|
} else if encoding == "gzip" {
|
||||||
// Header claims gzip but no magic bytes - this is a buggy server
|
// Header claims gzip but no magic bytes - check if client already handled decompression
|
||||||
detectionMethod = "header_claims_gzip_but_no_magic_bytes"
|
detectionMethod = "header_claims_gzip_no_magic_bytes"
|
||||||
qe.Logger.Warning(&libpack_logger.LogMessage{
|
|
||||||
Message: "Server claims gzip encoding but data lacks gzip magic bytes - treating as plain JSON",
|
// Check if this looks like valid JSON (likely already decompressed by client)
|
||||||
Pairs: map[string]interface{}{
|
trimmed := bytes.TrimSpace(rawData)
|
||||||
"content_encoding_header": encoding,
|
if len(trimmed) > 0 && (trimmed[0] == '{' || trimmed[0] == '[') {
|
||||||
"detection_method": detectionMethod,
|
qe.Logger.Debug(&libpack_logger.LogMessage{
|
||||||
"first_few_bytes": string(rawData[:min(50, len(rawData))]),
|
Message: "Content-Encoding header indicates gzip but data appears to be JSON - likely auto-decompressed by HTTP client",
|
||||||
},
|
Pairs: map[string]interface{}{
|
||||||
})
|
"content_encoding_header": encoding,
|
||||||
// Treat as uncompressed since magic bytes are missing
|
"detection_method": detectionMethod,
|
||||||
finalData = rawData
|
"data_starts_with_json": true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
finalData = rawData
|
||||||
|
} else {
|
||||||
|
qe.Logger.Warning(&libpack_logger.LogMessage{
|
||||||
|
Message: "Content-Encoding header indicates gzip but no magic bytes and data doesn't look like JSON",
|
||||||
|
Pairs: map[string]interface{}{
|
||||||
|
"content_encoding_header": encoding,
|
||||||
|
"detection_method": detectionMethod,
|
||||||
|
"first_few_bytes": string(rawData[:min(50, len(rawData))]),
|
||||||
|
"data_size": len(rawData),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return fmt.Errorf("content encoding mismatch: header claims gzip but data has no gzip magic bytes and doesn't appear to be valid JSON")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// No compression indicated by header and no gzip magic bytes
|
// No compression indicated by header and no gzip magic bytes
|
||||||
detectionMethod = "plain_json"
|
detectionMethod = "plain_json"
|
||||||
|
|||||||
@@ -342,12 +342,12 @@ func (suite *Tests) TestQueryExecutor_executeQuery_gzipTrailingGarbage() {
|
|||||||
qe.client = malformedGzipServer.Client()
|
qe.client = malformedGzipServer.Client()
|
||||||
qe.cache = client.cache
|
qe.cache = client.cache
|
||||||
|
|
||||||
// This should fail with gzip decompression but fallback to treating as uncompressed
|
// This should fail with gzip decompression error
|
||||||
result, err := qe.executeQuery()
|
result, err := qe.executeQuery()
|
||||||
// The fallback should fail because the raw data (including gzip headers) is not valid JSON
|
// Should get proper gzip decompression error instead of trying to parse raw gzip as JSON
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
assert.Nil(result)
|
assert.Nil(result)
|
||||||
assert.Contains(err.Error(), "error unmarshalling HTTP response")
|
assert.Contains(err.Error(), "gzip decompression failed")
|
||||||
})
|
})
|
||||||
|
|
||||||
suite.T().Run("should handle gzip with valid JSON fallback", func(t *testing.T) {
|
suite.T().Run("should handle gzip with valid JSON fallback", func(t *testing.T) {
|
||||||
@@ -443,7 +443,7 @@ func (suite *Tests) TestQueryExecutor_executeQuery_gzipTrailingGarbage() {
|
|||||||
result, err := qe.executeQuery()
|
result, err := qe.executeQuery()
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
assert.Nil(result)
|
assert.Nil(result)
|
||||||
assert.Contains(err.Error(), "empty response data")
|
assert.Contains(err.Error(), "content encoding mismatch")
|
||||||
})
|
})
|
||||||
|
|
||||||
suite.T().Run("should handle partial gzip data", func(t *testing.T) {
|
suite.T().Run("should handle partial gzip data", func(t *testing.T) {
|
||||||
@@ -586,10 +586,10 @@ func (suite *Tests) TestQueryExecutor_executeQuery_gzipErrorScenarios() {
|
|||||||
qe.cache = client.cache
|
qe.cache = client.cache
|
||||||
|
|
||||||
result, err := qe.executeQuery()
|
result, err := qe.executeQuery()
|
||||||
// Should fail gzip decompression and fallback, but raw data won't be valid JSON
|
// Should fail gzip decompression with proper error message
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
assert.Nil(result)
|
assert.Nil(result)
|
||||||
assert.Contains(err.Error(), "error unmarshalling HTTP response")
|
assert.Contains(err.Error(), "gzip decompression failed")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,7 +811,7 @@ func (suite *Tests) TestQueryExecutor_executeQuery_intelligentGzipDetection() {
|
|||||||
result, err := qe.executeQuery()
|
result, err := qe.executeQuery()
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
assert.Nil(result)
|
assert.Nil(result)
|
||||||
assert.Contains(err.Error(), "empty response data")
|
assert.Contains(err.Error(), "content encoding mismatch")
|
||||||
})
|
})
|
||||||
|
|
||||||
suite.T().Run("should handle response with only gzip magic bytes but no valid gzip data", func(t *testing.T) {
|
suite.T().Run("should handle response with only gzip magic bytes but no valid gzip data", func(t *testing.T) {
|
||||||
@@ -843,10 +843,10 @@ func (suite *Tests) TestQueryExecutor_executeQuery_intelligentGzipDetection() {
|
|||||||
qe.cache = client.cache
|
qe.cache = client.cache
|
||||||
|
|
||||||
result, err := qe.executeQuery()
|
result, err := qe.executeQuery()
|
||||||
// Should detect gzip magic bytes, fail decompression, fallback to raw data, then fail JSON parsing
|
// Should detect gzip magic bytes, fail gzip reader creation with proper error
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
assert.Nil(result)
|
assert.Nil(result)
|
||||||
assert.Contains(err.Error(), "error unmarshalling HTTP response")
|
assert.Contains(err.Error(), "gzip reader creation failed")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user