[Git][wxwidgets/wxwidgets][master] 5 commits: wxQt: Fix wxRibbonBar sample crashes when trying to show the frame window

1 view
Skip to first unread message

Vadim Zeitlin (@_VZ_)

unread,
Jan 15, 2026, 9:17:53 AMJan 15
to wx-commi...@googlegroups.com

Vadim Zeitlin pushed to branch master at wxWidgets / wxWidgets

Commits:

  • 7bbd4b47
    by ali kettab at 2026-01-11T23:33:12+01:00
    wxQt: Fix wxRibbonBar sample crashes when trying to show the frame window
    
  • 953a0ea5
    by ali kettab at 2026-01-11T23:57:57+01:00
    wxQt: Remove assertion from wxDC::GetPixel() implementation
    
    This function can only be used with a wxMemoryDC. Attempting to use it with a
    wxPaintDC (or any other DC) will result in a crash, which can be observed when
    running the ribbondemo sample.
    
  • 23bab9e6
    by Ian McInerney at 2026-01-15T12:38:58+01:00
    Wrap wxCHECK macro inside a do{}while construct to protect it
    
    Before, it is just a bare if statement, which could pose issues if used
    as the only statement in a single-line control flow construct, where the
    else clause could get associated with the wrong if statement.
    
    Closes #26096.
    
  • 9a767574
    by Vadim Zeitlin at 2026-01-15T14:51:36+01:00
    Add wxWebRequestDebugLogger for details logging of HTTP transfers
    
    Allow getting detailed information about the operations performed by
    wxWebRequest, at least when using libcurl-based backend, which provides
    good built-in support for this, and partially when using WinHTTP.
    
    Note that the debug logger is set at the session level and not for each
    request: this is less flexible, but more convenient and is probably how
    it will always be used in practice.
    
    See #26086.
    
  • 52998106
    by Vadim Zeitlin at 2026-01-15T14:52:51+01:00
    Merge branch 'ribbon-qt-fixes' of github.com:AliKet/wxWidgets
    
    Fix wxRibbonBar crashing under wxQt.
    
    See #26093.
    

12 changed files:

Changes:

  • include/wx/debug.h
    ... ... @@ -354,6 +354,7 @@ extern void WXDLLIMPEXP_BASE wxAbort();
    354 354
     // the generic macro: takes the condition to check, the statement to be executed
    
    355 355
     // in case the condition is false and the message to pass to the assert handler
    
    356 356
     #define wxCHECK2_MSG(cond, op, msg)                                       \
    
    357
    +    wxSTATEMENT_MACRO_BEGIN                                               \
    
    357 358
         if ( cond )                                                           \
    
    358 359
         {}                                                                    \
    
    359 360
         else                                                                  \
    
    ... ... @@ -361,7 +362,7 @@ extern void WXDLLIMPEXP_BASE wxAbort();
    361 362
             wxFAIL_COND_MSG(#cond, msg);                                      \
    
    362 363
             op;                                                               \
    
    363 364
         }                                                                     \
    
    364
    -    struct wxMAKE_UNIQUE_NAME(wxDummyCheckStruct) /* to force a semicolon */
    
    365
    +    wxSTATEMENT_MACRO_END
    
    365 366
     
    
    366 367
     // check which returns with the specified return code if the condition fails
    
    367 368
     #define wxCHECK_MSG(cond, rc, msg)   wxCHECK2_MSG(cond, return rc, msg)
    

  • include/wx/msw/private/webrequest_winhttp.h
    ... ... @@ -170,6 +170,10 @@ private:
    170 170
             return Fail(operation, ::GetLastError());
    
    171 171
         }
    
    172 172
     
    
    173
    +    // Log all the headers of the response if debug logging is enabled.
    
    174
    +    void LogResponseHeadersIfNecessary();
    
    175
    +
    
    176
    +
    
    173 177
         // These functions can only be used for asynchronous requests.
    
    174 178
         void SetFailed(const wxString& operation, DWORD errorCode)
    
    175 179
         {
    

  • include/wx/private/webrequest.h
    ... ... @@ -362,11 +362,22 @@ public:
    362 362
     
    
    363 363
         virtual bool EnablePersistentStorage(bool WXUNUSED(enable)) { return false; }
    
    364 364
     
    
    365
    +    void SetDebugLogger(std::unique_ptr<wxWebRequestDebugLogger> logger)
    
    366
    +        { m_debugLogger = std::move(logger); }
    
    367
    +
    
    368
    +    // Return raw, non owning pointer to the debug logger (may be null).
    
    369
    +    wxWebRequestDebugLogger* GetDebugLogger() const
    
    370
    +        { return m_debugLogger.get(); }
    
    371
    +
    
    365 372
     protected:
    
    366 373
         explicit wxWebSessionImpl(Mode mode);
    
    367 374
     
    
    368 375
         bool IsAsync() const { return m_mode == Mode::Async; }
    
    369 376
     
    
    377
    +
    
    378
    +    // If non-null, use it to log debug information.
    
    379
    +    std::unique_ptr<wxWebRequestDebugLogger> m_debugLogger;
    
    380
    +
    
    370 381
     private:
    
    371 382
         // Make it a friend to allow accessing our m_headers.
    
    372 383
         friend class wxWebRequest;
    

  • include/wx/webrequest.h
    ... ... @@ -135,6 +135,37 @@ protected:
    135 135
         wxWebResponseImplPtr m_impl;
    
    136 136
     };
    
    137 137
     
    
    138
    +// Base class for logging debug information from web requests.
    
    139
    +class wxWebRequestDebugLogger
    
    140
    +{
    
    141
    +public:
    
    142
    +    wxWebRequestDebugLogger() = default;
    
    143
    +    virtual ~wxWebRequestDebugLogger() = default;
    
    144
    +
    
    145
    +    // Informational message not directly corresponding to any data sent or
    
    146
    +    // received.
    
    147
    +    virtual void OnInfo(const wxString& info) = 0;
    
    148
    +
    
    149
    +    // Request sent to the server, e.g.  "GET /index.html HTTP/1.1".
    
    150
    +    virtual void OnRequestSent(const wxString& line) = 0;
    
    151
    +
    
    152
    +    // Response received from the server, e.g. "HTTP/1.1 200 OK".
    
    153
    +    virtual void OnResponseReceived(const wxString& line) = 0;
    
    154
    +
    
    155
    +    // Header sent to the server.
    
    156
    +    virtual void OnHeaderSent(const wxString& name, const wxString& value) = 0;
    
    157
    +
    
    158
    +    // Header received from the server.
    
    159
    +    virtual void OnHeaderReceived(const wxString& name, const wxString& value) = 0;
    
    160
    +
    
    161
    +    // Data sent to the server. This data may be binary and encrypted when
    
    162
    +    // using HTTPS, so it is typically not human-readable.
    
    163
    +    virtual void OnDataSent(const void* data, size_t size) = 0;
    
    164
    +
    
    165
    +    // Data received from the server. Same remarks as for OnDataSent() apply.
    
    166
    +    virtual void OnDataReceived(const void* data, size_t size) = 0;
    
    167
    +};
    
    168
    +
    
    138 169
     class WXDLLIMPEXP_NET wxWebRequestBase
    
    139 170
     {
    
    140 171
     public:
    
    ... ... @@ -395,6 +426,8 @@ public:
    395 426
     
    
    396 427
         bool EnablePersistentStorage(bool enable = true);
    
    397 428
     
    
    429
    +    void SetDebugLogger(std::unique_ptr<wxWebRequestDebugLogger> logger);
    
    430
    +
    
    398 431
         wxWebSessionHandle GetNativeHandle() const;
    
    399 432
     
    
    400 433
     private:
    

  • interface/wx/dc.h
    ... ... @@ -873,6 +873,8 @@ public:
    873 873
     
    
    874 874
             @note This method shouldn't be used with wxPaintDC as accessing the DC
    
    875 875
             while drawing can result in unexpected results, notably in wxGTK.
    
    876
    +
    
    877
    +        @note This method can only be used with wxMemoryDC under wxQt.
    
    876 878
         */
    
    877 879
         bool GetPixel(wxCoord x, wxCoord y, wxColour* colour) const;
    
    878 880
     
    

  • interface/wx/webrequest.h
    ... ... @@ -1312,6 +1312,103 @@ public:
    1312 1312
         static wxWebProxy Default();
    
    1313 1313
     };
    
    1314 1314
     
    
    1315
    +/**
    
    1316
    +    Base class for logging debug information from web requests.
    
    1317
    +
    
    1318
    +    An object of a class derived from this one may be associated with a
    
    1319
    +    wxWebSession or wxWebSessionSync using wxWebSession::SetDebugLogger() in
    
    1320
    +    order to receive detailed information about the data exchanged with the
    
    1321
    +    HTTP server.
    
    1322
    +
    
    1323
    +    Once this object is associated with a session, its member functions will be
    
    1324
    +    called to report various events happening during the request processing.
    
    1325
    +
    
    1326
    +    libcurl-based backend provides the most full-featured logging, with WinHTTP
    
    1327
    +    backend providing only limited information and NSURLSession-based backend
    
    1328
    +    currently not providing any logging at all.
    
    1329
    +
    
    1330
    +    @since 3.3.2
    
    1331
    +
    
    1332
    +    @library{wxnet}
    
    1333
    +    @category{net}
    
    1334
    +*/
    
    1335
    +class wxWebRequestDebugLogger
    
    1336
    +{
    
    1337
    +public:
    
    1338
    +    /// Default constructor.
    
    1339
    +    wxWebRequestDebugLogger() = default;
    
    1340
    +
    
    1341
    +    /**
    
    1342
    +        Called to notify about an informational message.
    
    1343
    +
    
    1344
    +        For example, the libcurl-based backend provides details about the
    
    1345
    +        protocol used (including TLS version when applicable) and the
    
    1346
    +        connection state using this function.
    
    1347
    +
    
    1348
    +        @param info A single line informational message.
    
    1349
    +     */
    
    1350
    +    virtual void OnInfo(const wxString& info) = 0;
    
    1351
    +
    
    1352
    +    /**
    
    1353
    +        Called with the request line sent to the server.
    
    1354
    +
    
    1355
    +        A typical example of such a line would be `GET /index.html HTTP/1.1`.
    
    1356
    +     */
    
    1357
    +    virtual void OnRequestSent(const wxString& line) = 0;
    
    1358
    +
    
    1359
    +    /**
    
    1360
    +        Called with the status line received from the server.
    
    1361
    +
    
    1362
    +        A typical example of such a line would be `HTTP/1.1 200 OK`.
    
    1363
    +     */
    
    1364
    +    virtual void OnResponseReceived(const wxString& line) = 0;
    
    1365
    +
    
    1366
    +    /**
    
    1367
    +        Called for each header sent to the server.
    
    1368
    +
    
    1369
    +        This is currently only called when libcurl-based backend is used.
    
    1370
    +
    
    1371
    +        @param name Name of the header
    
    1372
    +        @param value String value of the header
    
    1373
    +     */
    
    1374
    +    virtual void OnHeaderSent(const wxString& name, const wxString& value) = 0;
    
    1375
    +
    
    1376
    +    /**
    
    1377
    +        Called for each header received from the server.
    
    1378
    +
    
    1379
    +        @param name Name of the header
    
    1380
    +        @param value String value of the header
    
    1381
    +     */
    
    1382
    +    virtual void OnHeaderReceived(const wxString& name, const wxString& value) = 0;
    
    1383
    +
    
    1384
    +    /**
    
    1385
    +        Called when other data is sent to the server.
    
    1386
    +
    
    1387
    +        This data may be binary and encrypted when using HTTPS, so it is
    
    1388
    +        typically not human-readable, although it may be in some cases (e.g.
    
    1389
    +        when using a text body with HTTP POST).
    
    1390
    +
    
    1391
    +        This is currently only called when libcurl-based backend is used or
    
    1392
    +        when WinHTTP backend is used with synchronous requests.
    
    1393
    +
    
    1394
    +        @param data Pointer to the received data buffer.
    
    1395
    +        @param size Size of the received data buffer in bytes.
    
    1396
    +     */
    
    1397
    +    virtual void OnDataSent(const void* data, size_t size) = 0;
    
    1398
    +
    
    1399
    +    /**
    
    1400
    +        Called when other data is received from the server.
    
    1401
    +
    
    1402
    +        This data may be binary and encrypted when using HTTPS, so it is
    
    1403
    +        typically not human-readable, although it may be in some cases (e.g.
    
    1404
    +        when receiving a text response body).
    
    1405
    +
    
    1406
    +        @param data Pointer to the received data buffer.
    
    1407
    +        @param size Size of the received data buffer in bytes.
    
    1408
    +     */
    
    1409
    +    virtual void OnDataReceived(const void* data, size_t size) = 0;
    
    1410
    +};
    
    1411
    +
    
    1315 1412
     /**
    
    1316 1413
         @class wxWebSession
    
    1317 1414
     
    
    ... ... @@ -1530,6 +1627,21 @@ public:
    1530 1627
             @since 3.3.0
    
    1531 1628
          */
    
    1532 1629
         bool EnablePersistentStorage(bool enable);
    
    1630
    +
    
    1631
    +    /**
    
    1632
    +        Enable debug logging for all requests created by this session.
    
    1633
    +
    
    1634
    +        If @a logger is non-null, it will be used to log detailed debug
    
    1635
    +        information about the data exchanged with the HTTP server for all
    
    1636
    +        requests created by this session after this function is called.
    
    1637
    +
    
    1638
    +        @note Calling this function destroys any previously set logger, make
    
    1639
    +            sure there are no active requests using it any more before doing
    
    1640
    +            so to avoid crashes.
    
    1641
    +
    
    1642
    +        @since 3.3.2
    
    1643
    +     */
    
    1644
    +    void SetDebugLogger(std::unique_ptr<wxWebRequestDebugLogger> logger);
    
    1533 1645
     };
    
    1534 1646
     
    
    1535 1647
     /**
    
    ... ... @@ -1721,6 +1833,21 @@ public:
    1721 1833
             @note This is only implemented in the macOS backend.
    
    1722 1834
          */
    
    1723 1835
         bool EnablePersistentStorage(bool enable);
    
    1836
    +
    
    1837
    +    /**
    
    1838
    +        Enable debug logging for all requests created by this session.
    
    1839
    +
    
    1840
    +        If @a logger is non-null, it will be used to log detailed debug
    
    1841
    +        information about the data exchanged with the HTTP server for all
    
    1842
    +        requests created by this session after this function is called.
    
    1843
    +
    
    1844
    +        @note Calling this function destroys any previously set logger, make
    
    1845
    +            sure there are no active requests using it any more before doing
    
    1846
    +            so to avoid crashes.
    
    1847
    +
    
    1848
    +        @since 3.3.2
    
    1849
    +     */
    
    1850
    +    void SetDebugLogger(std::unique_ptr<wxWebRequestDebugLogger> logger);
    
    1724 1851
     };
    
    1725 1852
     
    
    1726 1853
     
    

  • src/common/webrequest.cpp
    ... ... @@ -1236,6 +1236,14 @@ bool wxWebSessionBase::EnablePersistentStorage(bool enable)
    1236 1236
         return m_impl->EnablePersistentStorage(enable);
    
    1237 1237
     }
    
    1238 1238
     
    
    1239
    +void
    
    1240
    +wxWebSessionBase::SetDebugLogger(std::unique_ptr<wxWebRequestDebugLogger> logger)
    
    1241
    +{
    
    1242
    +    wxCHECK_IMPL_VOID();
    
    1243
    +
    
    1244
    +    m_impl->SetDebugLogger(std::move(logger));
    
    1245
    +}
    
    1246
    +
    
    1239 1247
     // ----------------------------------------------------------------------------
    
    1240 1248
     // Module ensuring all global/singleton objects are destroyed on shutdown.
    
    1241 1249
     // ----------------------------------------------------------------------------
    

  • src/common/webrequest_curl.cpp
    ... ... @@ -346,6 +346,89 @@ static int wxCURLSeek(void* userdata, curl_off_t offset, int origin)
    346 346
         return static_cast<wxWebRequestCURL*>(userdata)->CURLOnSeek(offset, origin);
    
    347 347
     }
    
    348 348
     
    
    349
    +static int
    
    350
    +wxCURLDebugFunction(CURL* WXUNUSED(handle),
    
    351
    +                    curl_infotype type,
    
    352
    +                    char* data,
    
    353
    +                    size_t size,
    
    354
    +                    void* userdata)
    
    355
    +{
    
    356
    +    wxCHECK_MSG( userdata, 0, "invalid curl debug function data" );
    
    357
    +
    
    358
    +    auto* const logger = static_cast<wxWebRequestDebugLogger*>(userdata);
    
    359
    +    wxString text;
    
    360
    +    switch ( type )
    
    361
    +    {
    
    362
    +        case CURLINFO_TEXT:
    
    363
    +        case CURLINFO_HEADER_IN:
    
    364
    +        case CURLINFO_HEADER_OUT:
    
    365
    +            text = wxString::FromUTF8(data, size);
    
    366
    +            break;
    
    367
    +
    
    368
    +        case CURLINFO_DATA_IN:
    
    369
    +        case CURLINFO_SSL_DATA_IN:
    
    370
    +            logger->OnDataReceived(data, size);
    
    371
    +            break;
    
    372
    +
    
    373
    +        case CURLINFO_DATA_OUT:
    
    374
    +        case CURLINFO_SSL_DATA_OUT:
    
    375
    +            logger->OnDataSent(data, size);
    
    376
    +            break;
    
    377
    +
    
    378
    +        case CURLINFO_END:
    
    379
    +            wxFAIL_MSG("Unexpected CURLINFO_END info type in debug function");
    
    380
    +            break;
    
    381
    +    }
    
    382
    +
    
    383
    +    if ( !text.empty() )
    
    384
    +    {
    
    385
    +        // Remove trailing newline added by libcurl.
    
    386
    +        text.Trim();
    
    387
    +
    
    388
    +        if ( type == CURLINFO_TEXT )
    
    389
    +        {
    
    390
    +            // Informational messages are always on single line, so we don't
    
    391
    +            // need to do anything else with them.
    
    392
    +            logger->OnInfo(text);
    
    393
    +        }
    
    394
    +        else // Header or similar.
    
    395
    +        {
    
    396
    +            // We may have multiple lines and each of them may be either a
    
    397
    +            // header or a request/status line as libcurl reports both of them
    
    398
    +            // in the same way.
    
    399
    +            for ( auto const& line: wxSplit(text, '\n') )
    
    400
    +            {
    
    401
    +                wxString value;
    
    402
    +                auto const name = line.BeforeFirst(':', &value);
    
    403
    +
    
    404
    +                // A correct "start line" (from RFC 7230) can't include a colon
    
    405
    +                // before a space, so this is a simple way to distinguish it
    
    406
    +                // from a header field.
    
    407
    +                if ( value.empty() || name.find(' ') != wxString::npos )
    
    408
    +                {
    
    409
    +                    if ( type == CURLINFO_HEADER_IN )
    
    410
    +                        logger->OnResponseReceived(line);
    
    411
    +                    else // CURLINFO_HEADER_OUT
    
    412
    +                        logger->OnRequestSent(line);
    
    413
    +                }
    
    414
    +                else
    
    415
    +                {
    
    416
    +                    // Remove leading space, if any.
    
    417
    +                    value.Trim(false);
    
    418
    +
    
    419
    +                    if ( type == CURLINFO_HEADER_IN )
    
    420
    +                        logger->OnHeaderReceived(name, value);
    
    421
    +                    else // CURLINFO_HEADER_OUT
    
    422
    +                        logger->OnHeaderSent(name, value);
    
    423
    +                }
    
    424
    +            }
    
    425
    +        }
    
    426
    +    }
    
    427
    +
    
    428
    +    // We must always return 0 according to libcurl documentation.
    
    429
    +    return 0;
    
    430
    +}
    
    431
    +
    
    349 432
     wxWebRequestCURL::wxWebRequestCURL(wxWebSession & session,
    
    350 433
                                        wxWebSessionCURL& sessionImpl,
    
    351 434
                                        wxEvtHandler* handler,
    
    ... ... @@ -529,6 +612,15 @@ wxWebRequest::Result wxWebRequestCURL::DoFinishPrepare()
    529 612
         if ( securityFlags & wxWebRequest::Ignore_Host )
    
    530 613
             wxCURLSetOpt(m_handle, CURLOPT_SSL_VERIFYHOST, 0);
    
    531 614
     
    
    615
    +
    
    616
    +    // Enable debug logging if requested.
    
    617
    +    if ( auto const* logger = GetSessionImpl().GetDebugLogger() )
    
    618
    +    {
    
    619
    +        wxCURLSetOpt(m_handle, CURLOPT_DEBUGDATA, logger);
    
    620
    +        wxCURLSetOpt(m_handle, CURLOPT_DEBUGFUNCTION, wxCURLDebugFunction);
    
    621
    +        wxCURLSetOpt(m_handle, CURLOPT_VERBOSE, 1L);
    
    622
    +    }
    
    623
    +
    
    532 624
         return Result::Ok();
    
    533 625
     }
    
    534 626
     
    

  • src/msw/webrequest_winhttp.cpp
    ... ... @@ -134,6 +134,9 @@ wxWinHTTP::WinHttpSetTimeouts_t wxWinHTTP::WinHttpSetTimeouts;
    134 134
     #ifndef WINHTTP_PROTOCOL_FLAG_HTTP2
    
    135 135
     #define WINHTTP_PROTOCOL_FLAG_HTTP2 0x1
    
    136 136
     #endif
    
    137
    +#ifndef WINHTTP_PROTOCOL_FLAG_HTTP3
    
    138
    +#define WINHTTP_PROTOCOL_FLAG_HTTP3 0x2
    
    139
    +#endif
    
    137 140
     #ifndef WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL
    
    138 141
     #define WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL 133
    
    139 142
     #endif
    
    ... ... @@ -347,12 +350,18 @@ wxWebRequestWinHTTP::HandleCallback(DWORD dwInternetStatus,
    347 350
             case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
    
    348 351
                 if ( dwStatusInformationLength > 0 )
    
    349 352
                 {
    
    353
    +                if ( auto* const logger = GetSessionImpl().GetDebugLogger() )
    
    354
    +                    logger->OnDataReceived(lpvStatusInformation, dwStatusInformationLength);
    
    355
    +
    
    350 356
                     m_response->ReportDataReceived(dwStatusInformationLength);
    
    351 357
                     if ( !m_response->ReadData() && !WasCancelled() )
    
    352 358
                         SetFailedWithLastError("Reading data");
    
    353 359
                 }
    
    354 360
                 else
    
    355 361
                 {
    
    362
    +                if ( auto* const logger = GetSessionImpl().GetDebugLogger() )
    
    363
    +                    logger->OnInfo("Request completed");
    
    364
    +
    
    356 365
                     SetFinalStateFromStatus();
    
    357 366
                 }
    
    358 367
                 break;
    
    ... ... @@ -445,6 +454,8 @@ void wxWebRequestWinHTTP::WriteData()
    445 454
                     break;
    
    446 455
             }
    
    447 456
     
    
    457
    +        LogResponseHeadersIfNecessary();
    
    458
    +
    
    448 459
             // Start reading the response, even in unauthorized case.
    
    449 460
             if ( !m_response->ReadData() )
    
    450 461
                 SetFailedWithLastError("Reading data");
    
    ... ... @@ -452,6 +463,8 @@ void wxWebRequestWinHTTP::WriteData()
    452 463
             return;
    
    453 464
         }
    
    454 465
     
    
    466
    +    LogResponseHeadersIfNecessary();
    
    467
    +
    
    455 468
         CheckResult(DoWriteData());
    
    456 469
     }
    
    457 470
     
    
    ... ... @@ -481,6 +494,12 @@ wxWebRequest::Result wxWebRequestWinHTTP::DoWriteData(DWORD* numWritten)
    481 494
             return FailWithLastError("Writing data");
    
    482 495
         }
    
    483 496
     
    
    497
    +    if ( numWritten && *numWritten )
    
    498
    +    {
    
    499
    +        if ( auto* const logger = GetSessionImpl().GetDebugLogger() )
    
    500
    +            logger->OnDataSent(buffer, *numWritten);
    
    501
    +    }
    
    502
    +
    
    484 503
         return Result::Ok();
    
    485 504
     }
    
    486 505
     
    
    ... ... @@ -642,6 +661,8 @@ wxWebRequest::Result wxWebRequestWinHTTP::Execute()
    642 661
             continue;
    
    643 662
         }
    
    644 663
     
    
    664
    +    LogResponseHeadersIfNecessary();
    
    665
    +
    
    645 666
         // Read the response data.
    
    646 667
         for ( ;; )
    
    647 668
         {
    
    ... ... @@ -656,6 +677,9 @@ wxWebRequest::Result wxWebRequestWinHTTP::Execute()
    656 677
         }
    
    657 678
     
    
    658 679
         // We're done.
    
    680
    +    if ( auto* const logger = GetSessionImpl().GetDebugLogger() )
    
    681
    +        logger->OnInfo("Request completed");
    
    682
    +
    
    659 683
         return GetResultFromHTTPStatus(m_response);
    
    660 684
     }
    
    661 685
     
    
    ... ... @@ -684,12 +708,19 @@ wxWebRequest::Result wxWebRequestWinHTTP::DoPrepareRequest()
    684 708
             m_tryCredentialsFromURL = true;
    
    685 709
         }
    
    686 710
     
    
    711
    +    const wxString host(urlComps.lpszHostName, urlComps.dwHostNameLength);
    
    712
    +    const INTERNET_PORT port = urlComps.nPort;
    
    713
    +
    
    714
    +    auto* const logger = GetSessionImpl().GetDebugLogger();
    
    715
    +    if ( logger )
    
    716
    +        logger->OnInfo(wxString::Format("Connecting to %s:%u", host, port));
    
    717
    +
    
    687 718
         // Open a connection
    
    688 719
         m_connect = wxWinHTTP::WinHttpConnect
    
    689 720
                     (
    
    690 721
                          m_sessionImpl.GetHandle(),
    
    691
    -                     wxString(urlComps.lpszHostName, urlComps.dwHostNameLength).wc_str(),
    
    692
    -                     urlComps.nPort,
    
    722
    +                     host.wc_str(),
    
    723
    +                     port,
    
    693 724
                          wxRESERVED_PARAM
    
    694 725
                     );
    
    695 726
         if ( m_connect == nullptr )
    
    ... ... @@ -719,6 +750,50 @@ wxWebRequest::Result wxWebRequestWinHTTP::DoPrepareRequest()
    719 750
             return FailWithLastError("Opening request");
    
    720 751
         }
    
    721 752
     
    
    753
    +    if ( logger )
    
    754
    +    {
    
    755
    +        // Synthesize the request line for logging purposes only: for this, we
    
    756
    +        // need to get the HTTP version used by WinHTTP.
    
    757
    +        DWORD httpVersion = 0;
    
    758
    +        DWORD size = sizeof(httpVersion);
    
    759
    +        if ( wxWinHTTP::WinHttpQueryOption
    
    760
    +                        (
    
    761
    +                            m_request,
    
    762
    +                            WINHTTP_OPTION_HTTP_PROTOCOL_USED,
    
    763
    +                            &httpVersion,
    
    764
    +                            &size
    
    765
    +                        ) )
    
    766
    +        {
    
    767
    +            wxString httpStr;
    
    768
    +            switch ( httpVersion )
    
    769
    +            {
    
    770
    +                case 0:
    
    771
    +                    // Default value meaning HTTP/1.1.
    
    772
    +                    httpStr = "1.1";
    
    773
    +                    break;
    
    774
    +
    
    775
    +                case WINHTTP_PROTOCOL_FLAG_HTTP2:
    
    776
    +                    httpStr = "2";
    
    777
    +                    break;
    
    778
    +
    
    779
    +                case WINHTTP_PROTOCOL_FLAG_HTTP3:
    
    780
    +                    httpStr = "3";
    
    781
    +                    break;
    
    782
    +
    
    783
    +                default:
    
    784
    +                    httpStr = wxString::Format("unknown (%u)", httpVersion);
    
    785
    +                    break;
    
    786
    +            }
    
    787
    +
    
    788
    +            if ( objectName.empty() )
    
    789
    +                objectName = "/";
    
    790
    +
    
    791
    +            logger->OnRequestSent(
    
    792
    +                wxString::Format("%s %s HTTP/%s", method, objectName, httpStr)
    
    793
    +            );
    
    794
    +        }
    
    795
    +    }
    
    796
    +
    
    722 797
         if ( int flags = GetSecurityFlags() )
    
    723 798
         {
    
    724 799
             DWORD optValue = 0;
    
    ... ... @@ -834,6 +909,9 @@ wxWebRequest::Result wxWebRequestWinHTTP::SendRequest()
    834 909
             return FailWithLastError("Sending request");
    
    835 910
         }
    
    836 911
     
    
    912
    +    if ( auto* const logger = GetSessionImpl().GetDebugLogger() )
    
    913
    +        logger->OnInfo("Headers sent");
    
    914
    +
    
    837 915
         return Result::Ok();
    
    838 916
     }
    
    839 917
     
    
    ... ... @@ -843,6 +921,47 @@ void wxWebRequestWinHTTP::DoCancel()
    843 921
         m_request = nullptr;
    
    844 922
     }
    
    845 923
     
    
    924
    +void wxWebRequestWinHTTP::LogResponseHeadersIfNecessary()
    
    925
    +{
    
    926
    +    auto* const logger = GetSessionImpl().GetDebugLogger();
    
    927
    +    if ( !logger )
    
    928
    +        return;
    
    929
    +
    
    930
    +    auto const
    
    931
    +        headers = wxWinHTTPQueryHeaderString(m_request, WINHTTP_QUERY_RAW_HEADERS_CRLF);
    
    932
    +
    
    933
    +    bool seenStatus = false;
    
    934
    +    for ( size_t pos = 0;; )
    
    935
    +    {
    
    936
    +        const size_t end = headers.find("\r\n", pos);
    
    937
    +
    
    938
    +        if ( end == wxString::npos )
    
    939
    +            break;
    
    940
    +
    
    941
    +        const wxString line = headers.substr(pos, end - pos);
    
    942
    +        if ( line.empty() )
    
    943
    +            break;
    
    944
    +
    
    945
    +        pos = end + 2;
    
    946
    +
    
    947
    +        if ( !seenStatus )
    
    948
    +        {
    
    949
    +            logger->OnResponseReceived(line);
    
    950
    +
    
    951
    +            seenStatus = true;
    
    952
    +            continue;
    
    953
    +        }
    
    954
    +
    
    955
    +        wxString value;
    
    956
    +        auto const name = line.BeforeFirst(':', &value);
    
    957
    +
    
    958
    +        // Remove leading space, if any.
    
    959
    +        value.Trim(false);
    
    960
    +
    
    961
    +        logger->OnHeaderReceived(name, value);
    
    962
    +    }
    
    963
    +}
    
    964
    +
    
    846 965
     //
    
    847 966
     // wxWebResponseWinHTTP
    
    848 967
     //
    
    ... ... @@ -916,13 +1035,23 @@ bool wxWebResponseWinHTTP::ReadData(DWORD* bytesRead)
    916 1035
     {
    
    917 1036
         wxLogTrace(wxTRACE_WEBREQUEST, "Request %p: reading data", &m_request);
    
    918 1037
     
    
    919
    -    return wxWinHTTP::WinHttpReadData
    
    1038
    +    void* const data = GetDataBuffer(wxWEBREQUEST_BUFFER_SIZE);
    
    1039
    +    if ( !wxWinHTTP::WinHttpReadData
    
    920 1040
                  (
    
    921 1041
                     m_requestHandle,
    
    922
    -                GetDataBuffer(wxWEBREQUEST_BUFFER_SIZE),
    
    1042
    +                data,
    
    923 1043
                     wxWEBREQUEST_BUFFER_SIZE,
    
    924 1044
                     bytesRead    // [out] bytes read, must be null in async mode
    
    925
    -             ) == TRUE;
    
    1045
    +             ) )
    
    1046
    +        return false;
    
    1047
    +
    
    1048
    +    if ( bytesRead && *bytesRead )
    
    1049
    +    {
    
    1050
    +        if ( auto* const logger = m_request.GetSessionImpl().GetDebugLogger() )
    
    1051
    +            logger->OnDataReceived(data, *bytesRead);
    
    1052
    +    }
    
    1053
    +
    
    1054
    +    return true;
    
    926 1055
     }
    
    927 1056
     
    
    928 1057
     //
    

  • src/qt/dc.cpp
    ... ... @@ -669,18 +669,19 @@ bool wxQtDCImpl::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
    669 669
     
    
    670 670
         if ( col )
    
    671 671
         {
    
    672
    -        wxCHECK_MSG( m_qtPixmap != nullptr, false, "This DC doesn't support GetPixel()" );
    
    673
    -        QPixmap pixmap1px = m_qtPixmap->copy( x, y, 1, 1 );
    
    674
    -        QImage image = pixmap1px.toImage();
    
    675
    -        QColor pixel = image.pixel( 0, 0 );
    
    676
    -        col->Set( pixel.red(), pixel.green(), pixel.blue(), pixel.alpha() );
    
    672
    +        if ( m_qtPixmap )
    
    673
    +        {
    
    674
    +            QPixmap pixmap1px = m_qtPixmap->copy( x, y, 1, 1 );
    
    675
    +            QImage image = pixmap1px.toImage();
    
    676
    +            QColor pixel = image.pixel( 0, 0 );
    
    677
    +            col->Set( pixel.red(), pixel.green(), pixel.blue(), pixel.alpha() );
    
    677 678
     
    
    678
    -        return true;
    
    679
    -    }
    
    680
    -    else
    
    681
    -    {
    
    682
    -        return false;
    
    679
    +            return true;
    
    680
    +        }
    
    681
    +        // else: This DC doesn't support GetPixel()
    
    683 682
         }
    
    683
    +
    
    684
    +    return false;
    
    684 685
     }
    
    685 686
     
    
    686 687
     void wxQtDCImpl::DoDrawPoint(wxCoord x, wxCoord y)
    

  • src/qt/window.cpp
    ... ... @@ -368,7 +368,21 @@ wxWindowQt::~wxWindowQt()
    368 368
     
    
    369 369
         DestroyChildren(); // This also destroys scrollbars
    
    370 370
     
    
    371
    -    delete m_qtWindow;
    
    371
    +    auto* const p = m_qtWindow->parentWidget();
    
    372
    +
    
    373
    +    if ( p && p->isVisible() && m_qtWindow->testAttribute(Qt::WA_PendingResizeEvent) )
    
    374
    +    {
    
    375
    +        // To prevent a potential use-after-delete error, m_qtWindow should not be deleted
    
    376
    +        // until after the parent window's QShowEvent handler has fully completed. IOW,
    
    377
    +        // this occurs when a child window is destroyed while the parent is in the middle
    
    378
    +        // of showing its children in the QShowEvent handler.
    
    379
    +
    
    380
    +        m_qtWindow->deleteLater();
    
    381
    +    }
    
    382
    +    else
    
    383
    +    {
    
    384
    +        delete m_qtWindow;
    
    385
    +    }
    
    372 386
     }
    
    373 387
     
    
    374 388
     
    

  • tests/net/webrequest.cpp
    ... ... @@ -24,6 +24,8 @@
    24 24
     #include "wx/uri.h"
    
    25 25
     #include "wx/wfstream.h"
    
    26 26
     
    
    27
    +#include "wx/private/make_unique.h"
    
    28
    +
    
    27 29
     #include <memory>
    
    28 30
     #include <unordered_map>
    
    29 31
     
    
    ... ... @@ -222,6 +224,54 @@ protected:
    222 224
     
    
    223 225
                 GetRequest().MakeInsecure(flags);
    
    224 226
             }
    
    227
    +
    
    228
    +        wxString debug;
    
    229
    +        if ( wxGetEnv("WX_TEST_WEBREQUEST_DEBUG", &debug ) )
    
    230
    +        {
    
    231
    +            class DebugLogger : public wxWebRequestDebugLogger
    
    232
    +            {
    
    233
    +            public:
    
    234
    +                virtual void OnInfo(const wxString& info) override
    
    235
    +                {
    
    236
    +                    wxFprintf(stderr, "// %s\n", info);
    
    237
    +                }
    
    238
    +
    
    239
    +                virtual void OnRequestSent(const wxString& line) override
    
    240
    +                {
    
    241
    +                    wxFprintf(stderr, "=> %s\n", line);
    
    242
    +                }
    
    243
    +
    
    244
    +                virtual void OnResponseReceived(const wxString& line) override
    
    245
    +                {
    
    246
    +                    wxFprintf(stderr, "<= %s\n", line);
    
    247
    +                }
    
    248
    +
    
    249
    +                virtual void OnHeaderSent(const wxString& name, const wxString& value) override
    
    250
    +                {
    
    251
    +                    wxFprintf(stderr, "-> %s: %s\n", name, value);
    
    252
    +                }
    
    253
    +
    
    254
    +                virtual void OnHeaderReceived(const wxString& name, const wxString& value) override
    
    255
    +                {
    
    256
    +                    wxFprintf(stderr, "<- %s: %s\n", name, value);
    
    257
    +                }
    
    258
    +
    
    259
    +                virtual void OnDataSent(const void* WXUNUSED(data), size_t size) override
    
    260
    +                {
    
    261
    +                    wxFprintf(stderr, "-> data (%zu bytes)\n", size);
    
    262
    +                }
    
    263
    +
    
    264
    +                virtual void OnDataReceived(const void* WXUNUSED(data), size_t size) override
    
    265
    +                {
    
    266
    +                    wxFprintf(stderr, "<- data (%zu bytes)\n", size);
    
    267
    +                }
    
    268
    +            };
    
    269
    +
    
    270
    +            if ( debug == "1" )
    
    271
    +                GetSession().SetDebugLogger(std::make_unique<DebugLogger>());
    
    272
    +            else
    
    273
    +                WARN("Unknown WX_TEST_WEBREQUEST_DEBUG value: " << debug);
    
    274
    +        }
    
    225 275
         }
    
    226 276
     
    
    227 277
     private:
    

Reply all
Reply to author
Forward
0 new messages