Issue importing media using containerized instance

My org ran into this issue when trying to set up a containerized Omeka S instance (v3.0.1) using an OpenShift cluster. The instance is unable to create media resources using the OEmbed and URL ingesters, throwing SSL-related exceptions when routed through the cluster’s proxy.

I haven’t done much web application development, and I’m looking for some direction about where to look next.

The first indication of the issue was when Omeka S failed on oembed links that worked on instances that weren’t containerized. The containerized instance reported the following runtime error:

Laminas\Http\Client\Adapter\Exception\RuntimeException
Unable to connect to HTTPS server through proxy: could not negotiate secure connection.

Details:

Laminas\Http\Client\Adapter\Exception\RuntimeException: Unable to connect to HTTPS server through proxy: could not negotiate secure connection. in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.php:296
Stack trace:
#0 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.php(165): Laminas\Http\Client\Adapter\Proxy->connectHandshake('vimeo.com', 443, '1.1', Array)
#1 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client.php(1457): Laminas\Http\Client\Adapter\Proxy->write('GET', Object(Laminas\Uri\Http), '1.1', Array, '')
#2 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client.php(945): Laminas\Http\Client->doRequest(Object(Laminas\Uri\Http), 'GET', true, Array, '')
#3 /opt/app-root/src/omeka-s/application/src/Media/Ingester/OEmbed.php(142): Laminas\Http\Client->send()
#4 /opt/app-root/src/omeka-s/application/src/Media/Ingester/OEmbed.php(73): Omeka\Media\Ingester\OEmbed->makeRequest('https://vimeo.c...', 'OEmbed URL', Object(Omeka\Stdlib\ErrorStore))
#5 /opt/app-root/src/omeka-s/application/src/Api/Adapter/MediaAdapter.php(159): Omeka\Media\Ingester\OEmbed->ingest(Object(Omeka\Entity\Media), Object(Omeka\Api\Request), Object(Omeka\Stdlib\ErrorStore))
#6 /opt/app-root/src/omeka-s/application/src/Api/Adapter/AbstractEntityAdapter.php(590): Omeka\Api\Adapter\MediaAdapter->hydrate(Object(Omeka\Api\Request), Object(Omeka\Entity\Media), Object(Omeka\Stdlib\ErrorStore))
#7 /opt/app-root/src/omeka-s/application/src/Api/Adapter/ItemAdapter.php(240): Omeka\Api\Adapter\AbstractEntityAdapter->hydrateEntity(Object(Omeka\Api\Request), Object(Omeka\Entity\Media), Object(Omeka\Stdlib\ErrorStore))
#8 /opt/app-root/src/omeka-s/application/src/Api/Adapter/AbstractEntityAdapter.php(590): Omeka\Api\Adapter\ItemAdapter->hydrate(Object(Omeka\Api\Request), Object(Omeka\Entity\Item), Object(Omeka\Stdlib\ErrorStore))
#9 /opt/app-root/src/omeka-s/application/src/Api/Adapter/AbstractEntityAdapter.php(318): Omeka\Api\Adapter\AbstractEntityAdapter->hydrateEntity(Object(Omeka\Api\Request), Object(Omeka\Entity\Item), Object(Omeka\Stdlib\ErrorStore))
#10 /opt/app-root/src/omeka-s/application/src/Api/Manager.php(224): Omeka\Api\Adapter\AbstractEntityAdapter->create(Object(Omeka\Api\Request))
#11 /opt/app-root/src/omeka-s/application/src/Api/Manager.php(78): Omeka\Api\Manager->execute(Object(Omeka\Api\Request))
#12 /opt/app-root/src/omeka-s/application/src/Mvc/Controller/Plugin/Api.php(99): Omeka\Api\Manager->create('items', Array, Array, Array)
#13 /opt/app-root/src/omeka-s/application/src/Controller/Admin/ItemController.php(207): Omeka\Mvc\Controller\Plugin\Api->create('items', Array, Array)
#14 /opt/app-root/src/omeka-s/vendor/laminas/laminas-mvc/src/Controller/AbstractActionController.php(77): Omeka\Controller\Admin\ItemController->addAction()
#15 /opt/app-root/src/omeka-s/vendor/laminas/laminas-eventmanager/src/EventManager.php(321): Laminas\Mvc\Controller\AbstractActionController->onDispatch(Object(Laminas\Mvc\MvcEvent))
#16 /opt/app-root/src/omeka-s/vendor/laminas/laminas-eventmanager/src/EventManager.php(178): Laminas\EventManager\EventManager->triggerListeners(Object(Laminas\Mvc\MvcEvent), Object(Closure))
#17 /opt/app-root/src/omeka-s/vendor/laminas/laminas-mvc/src/Controller/AbstractController.php(103): Laminas\EventManager\EventManager->triggerEventUntil(Object(Closure), Object(Laminas\Mvc\MvcEvent))
#18 /opt/app-root/src/omeka-s/vendor/laminas/laminas-mvc/src/DispatchListener.php(139): Laminas\Mvc\Controller\AbstractController->dispatch(Object(Laminas\Http\PhpEnvironment\Request), Object(Laminas\Http\PhpEnvironment\Response))
#19 /opt/app-root/src/omeka-s/vendor/laminas/laminas-eventmanager/src/EventManager.php(321): Laminas\Mvc\DispatchListener->onDispatch(Object(Laminas\Mvc\MvcEvent))
#20 /opt/app-root/src/omeka-s/vendor/laminas/laminas-eventmanager/src/EventManager.php(178): Laminas\EventManager\EventManager->triggerListeners(Object(Laminas\Mvc\MvcEvent), Object(Closure))
#21 /opt/app-root/src/omeka-s/vendor/laminas/laminas-mvc/src/Application.php(331): Laminas\EventManager\EventManager->triggerEventUntil(Object(Closure), Object(Laminas\Mvc\MvcEvent))
#22 /opt/app-root/src/omeka-s/index.php(21): Laminas\Mvc\Application->run()
#23 {main}

The runtime error was accompanied by the following php warnings captured in the container logs:

Warning: stream_socket_enable_crypto(): Peer certificate CN=`vimeo.map.fastly.net' did not match expected CN=`<http_config proxy_host value>' in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.php on line 289
Warning: stream_socket_enable_crypto(): SSL/TLS already set-up for this stream in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.php on line 289
Warning: stream_socket_enable_crypto(): SSL/TLS already set-up for this stream in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.php on line 289
Warning: stream_socket_enable_crypto(): SSL/TLS already set-up for this stream in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.php on line 289

The php warning led me to a stackoverflow answer for the Zend Framework. I disabled the ssl peer and peer name verification expecting to see the oembed start working. The initial result was a grab bag of errors that were further down the line, but I was able to successfully create media resources from oembed urls after retrying multiple times.

These new errors included the same proxy runtime error as above accompanied by a new php warning:

Warning: stream_socket_enable_crypto(): SSL: Handshake timed out in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.php on line 289

what appears to be an empty or malformed response from the oembed destination:

Laminas\Http\Exception\InvalidArgumentException
A valid response status line was not found in the provided string

Details:

Laminas\Http\Exception\InvalidArgumentException: A valid response status line was not found in the provided string in /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Response.php:266
Stack trace:
#0 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Response.php(204): Laminas\Http\Response->parseStatusLine('')
#1 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.php(271): Laminas\Http\Response::fromString('')
#2 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client/Adapter/Proxy.php(165): Laminas\Http\Client\Adapter\Proxy->connectHandshake('vimeo.com', 443, '1.1', Array)
#3 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client.php(1457): Laminas\Http\Client\Adapter\Proxy->write('GET', Object(Laminas\Uri\Http), '1.1', Array, '')
#4 /opt/app-root/src/omeka-s/vendor/laminas/laminas-http/src/Client.php(945): Laminas\Http\Client->doRequest(Object(Laminas\Uri\Http), 'GET', true, Array, '')
#5 /opt/app-root/src/omeka-s/application/src/Media/Ingester/OEmbed.php(142): Laminas\Http\Client->send()
#6 /opt/app-root/src/omeka-s/application/src/Media/Ingester/OEmbed.php(73): Omeka\Media\Ingester\OEmbed->makeRequest('https://vimeo.c...', 'OEmbed URL', Object(Omeka\Stdlib\ErrorStore))
#7 /opt/app-root/src/omeka-s/application/src/Api/Adapter/MediaAdapter.php(159): Omeka\Media\Ingester\OEmbed->ingest(Object(Omeka\Entity\Media), Object(Omeka\Api\Request), Object(Omeka\Stdlib\ErrorStore))
#8 /opt/app-root/src/omeka-s/application/src/Api/Adapter/AbstractEntityAdapter.php(590): Omeka\Api\Adapter\MediaAdapter->hydrate(Object(Omeka\Api\Request), Object(Omeka\Entity\Media), Object(Omeka\Stdlib\ErrorStore))
#9 /opt/app-root/src/omeka-s/application/src/Api/Adapter/ItemAdapter.php(240): Omeka\Api\Adapter\AbstractEntityAdapter->hydrateEntity(Object(Omeka\Api\Request), Object(Omeka\Entity\Media), Object(Omeka\Stdlib\ErrorStore))
#10 /opt/app-root/src/omeka-s/application/src/Api/Adapter/AbstractEntityAdapter.php(590): Omeka\Api\Adapter\ItemAdapter->hydrate(Object(Omeka\Api\Request), Object(Omeka\Entity\Item), Object(Omeka\Stdlib\ErrorStore))
#11 /opt/app-root/src/omeka-s/application/src/Api/Adapter/AbstractEntityAdapter.php(318): Omeka\Api\Adapter\AbstractEntityAdapter->hydrateEntity(Object(Omeka\Api\Request), Object(Omeka\Entity\Item), Object(Omeka\Stdlib\ErrorStore))
#12 /opt/app-root/src/omeka-s/application/src/Api/Manager.php(224): Omeka\Api\Adapter\AbstractEntityAdapter->create(Object(Omeka\Api\Request))
#13 /opt/app-root/src/omeka-s/application/src/Api/Manager.php(78): Omeka\Api\Manager->execute(Object(Omeka\Api\Request))
#14 /opt/app-root/src/omeka-s/application/src/Mvc/Controller/Plugin/Api.php(99): Omeka\Api\Manager->create('items', Array, Array, Array)
#15 /opt/app-root/src/omeka-s/application/src/Controller/Admin/ItemController.php(207): Omeka\Mvc\Controller\Plugin\Api->create('items', Array, Array)
#16 /opt/app-root/src/omeka-s/vendor/laminas/laminas-mvc/src/Controller/AbstractActionController.php(77): Omeka\Controller\Admin\ItemController->addAction()
#17 /opt/app-root/src/omeka-s/vendor/laminas/laminas-eventmanager/src/EventManager.php(321): Laminas\Mvc\Controller\AbstractActionController->onDispatch(Object(Laminas\Mvc\MvcEvent))
#18 /opt/app-root/src/omeka-s/vendor/laminas/laminas-eventmanager/src/EventManager.php(178): Laminas\EventManager\EventManager->triggerListeners(Object(Laminas\Mvc\MvcEvent), Object(Closure))
#19 /opt/app-root/src/omeka-s/vendor/laminas/laminas-mvc/src/Controller/AbstractController.php(103): Laminas\EventManager\EventManager->triggerEventUntil(Object(Closure), Object(Laminas\Mvc\MvcEvent))
#20 /opt/app-root/src/omeka-s/vendor/laminas/laminas-mvc/src/DispatchListener.php(139): Laminas\Mvc\Controller\AbstractController->dispatch(Object(Laminas\Http\PhpEnvironment\Request), Object(Laminas\Http\PhpEnvironment\Response))
#21 /opt/app-root/src/omeka-s/vendor/laminas/laminas-eventmanager/src/EventManager.php(321): Laminas\Mvc\DispatchListener->onDispatch(Object(Laminas\Mvc\MvcEvent))
#22 /opt/app-root/src/omeka-s/vendor/laminas/laminas-eventmanager/src/EventManager.php(178): Laminas\EventManager\EventManager->triggerListeners(Object(Laminas\Mvc\MvcEvent), Object(Closure))
#23 /opt/app-root/src/omeka-s/vendor/laminas/laminas-mvc/src/Application.php(331): Laminas\EventManager\EventManager->triggerEventUntil(Object(Closure), Object(Laminas\Mvc\MvcEvent))
#24 /opt/app-root/src/omeka-s/index.php(21): Laminas\Mvc\Application->run()
#25 {main}

and, in one instance, a 504 status code for the admin panel itself.

Another programmer at my org modified some of the base Omeka S application code to include functionality that allowed creating media resources using oembed urls for websites not supported by Omeka S by default.

I replaced the base omeka application files with our modified versions expecting to be able to create media resources for these urls in the same way described above. Trying to process oembed urls from the additional websites exhibited the same errors as above in addition to reporting a new http status code. I was not able to create any media resources from oembed urls for the additional websites.

“Successful” responses returned a 421 status code message in the admin panel. I have a feeling that this might be a separate issue, but I don’t think there’s a benefit to investigating it until the general oembed issue is addressed.

omeka warning: Error reading OEmbed URL: Misdirected Request (421)

We don’t really do anything “interesting” with how we make requests… I’d tend to point the finger at issues with the proxy or the container networking, particularly with handshake issues, the response status line going missing… that’s a variety of different but maybe problems, it seems to me.

Thanks for responding.

Some updates after working with the person who set up the container.

Other programs within the container that make http requests through the same proxy server work as expected. Examples include yum, curl, and the smtp program used to send emails from Omeka S.

After seeing that the curl command line tool work, I wrote a small test program using php’s curl library. None of the command line or test program requests failed, but I did see a variable response time. Some requests took 40+ seconds to complete.

Omeka S almost worked completely after switching to the laminas-http curl adapter. I could make items with oembed media without any runtime exceptions occurring. It seemed the item creation exhibited the same runtime variability as the command line tests. Some items returned 504 timeout response codes, but omeka appears to have successfully been able to create them as they were listed when I navigated back to the admin screen manually.

I’m not sure at which server (container apache, proxy, destination) is generating the 504 error codes.

'http_client' => [
        'adapter'    => \Laminas\Http\Client\Adapter\Curl::class,
        'proxy_host' => ‘<proxy.address>’,
        'proxy_port' => <proxy port>,
    ],

It seems the issue is specific to the interaction between the laminas proxy adapter, the proxy server, and/or the destination server.

Things I’m considering next:

Try to replicate the errors by routing a non-containerized instance through the proxy to determine whether the issue is specific to being inside a container.

Try to replicate the errors by writing a test program that uses the lamina-http client. Debugging this would be easier for me than using the full Omeka application as this time.

Tangential, is editing the original post disabled for new users or for all users?

1 Like