Get content-disposition from Request header for file download

I am automating some document download steps and need to create an index of all files attached to a unique ID separately in XLS.

At the moment I have this working by checking the last file name downloaded in a path, but this is unreliable:

a) because if a file is not created at a step it may look back to the previous one and assign a prior file to the wrong ID.
b) the same thing could happen if there is a large file download happens and it takes an unexpected amount of time before it continues with the next step.

So, I am hoping to solve this a different way- by getting the HTTP header content-disposition when the URL is clicked initially from ‘filename’ here. In this way I also don’t have to worry about whether the download has completed or not:

image

But as a newbie this is getting pretty deep into the technical weeds so looking for some help on how to get this filename from the header in UIPath

thanks!

1 Like

Hi @Charles,

Instead of clicking, can you make the request to the API directly? Because when clicking, a request will be made to the API anyway, so you could do it directly.

If so, you can use a HTTP Request activity (you need to install the UiPAth.WebAPI.Activities dependence)

Then, you can store the Headers in a variable and access the values

image

If this solves your problem, kindly mark this post as solution to close this topic.

If you need extra help and/or have any question, please let me know :slight_smile:

Thanks!

thanks, ok I will take a look- this is behind a portal so I’d need all the session info and not sure how complex it will be to manually build a request but will do some digging

1 Like

So this worked (kind of) and I get a PDF response as expected but then the UIPath model fails after running it with the below:

21.2.0-beta.44+Branch.release-v21.2.0.Sha.8ede47e8688d4fa0ba0ff6103ca2fe3ca36a426f

Exception has been thrown by the target of an invocation.

Error: System.Exception: Exception has been thrown by the target of an invocation.
 ---> System.Exception: Could not load type 'UiPath.Platform.ResourceHandling.ILocalResource' from assembly 'site.Platform, Version=21.2.0.0, Culture=neutral, PublicKeyToken=null'.
   at System.Signature.GetSignature(Void* pCorSig, Int32 cCorSig, RuntimeFieldHandleInternal fieldHandle, IRuntimeMethodInfo methodHandle, RuntimeType declaringType)
   at System.Reflection.RuntimeMethodInfo.FetchNonReturnParameters()
   at System.Reflection.RuntimeMethodInfo.GetParametersNoCopy()
   at System.Reflection.RuntimePropertyInfo.GetIndexParametersNoCopy()
   at System.Reflection.RuntimePropertyInfo.GetIndexParameters()
   at System.ComponentModel.ReflectTypeDescriptionProvider.ReflectGetProperties(Type type)
   at System.ComponentModel.ReflectTypeDescriptionProvider.ReflectedTypeData.GetProperties()
   at System.ComponentModel.TypeDescriptor.TypeDescriptionNode.DefaultTypeDescriptor.System.ComponentModel.ICustomTypeDescriptor.GetProperties()
   at System.Activities.Presentation.Metadata.MetadataStore.MetadataStoreProvider.MetadataStoreTypeDescriptor.System.ComponentModel.ICustomTypeDescriptor.GetProperties()
   at System.ComponentModel.TypeDescriptor.TypeDescriptionNode.DefaultTypeDescriptor.System.ComponentModel.ICustomTypeDescriptor.GetProperties()
   at System.ComponentModel.TypeDescriptor.TypeDescriptionNode.DefaultTypeDescriptor.System.ComponentModel.ICustomTypeDescriptor.GetProperties()
   at System.Activities.Presentation.Model.ModelPropertyCollectionImpl.GetPropertyDescriptors()
   at System.Activities.Presentation.Model.ModelPropertyCollectionImpl.<GetEnumerator>d__3.MoveNext()
   at System.Activities.Presentation.Internal.PropertyEditing.Model.ModelPropertyMerger.<GetFirstProperties>d__7.MoveNext()
   at System.Activities.Presentation.Internal.PropertyEditing.PropertyInspector.UpdateCategories(Selection selection, Boolean attachedOnly)
   at System.Activities.Presentation.Internal.PropertyEditing.PropertyInspector.RefreshPropertyList(Boolean attachedOnly)
   at System.Activities.Presentation.Internal.PropertyEditing.PropertyInspector.OnSelectionChangedIdle()
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler), HResult -2146232828
1 Like

Also it appears the package is regularly updated and maybe the most recent draft version doesnt match your screenshot- I reverted back to an older version to match your screen above with the HTTP client setup but there I’m getting a different response which is not successful either:

image

1 Like

Still a bit stuck so just going back to basics- I created a very simple model attached to visit a PDF URL and simply read the response header for a specific value.

HTTP_WebActivities.xaml (7.0 KB)
However this still does not work if you have any pointers here? Whenever I try to reference Header Content by key / value name it seems to not find anything.

In this attached example I just tried file size which is in the header response if you might be able to check and see why that is not working

1 Like

Hi @Charles,

Use the latest version, don’t worry about using the same one I’m using.

About the file you shared…

1 - Use Header_Out("Cotent-Length") instead of Header_Out("cotent-length"). Anyway, I think you are not interested in this value.
2 - I also noticed that the Header_Out does not contain the header you want (Content-Disposition). So, my question is… are you sure this request is the same as when you click on the URL?

Hi @gustavo.cervelin

thanks - yes I changed this to a public URL. The content- disposition filename ="" I wanted to get is behind a secure portal so I could not share that model).

However I was not successful in trying to read any response header value at all (including this one) so was hoping if at least I could read any header value at all then maybe I could figure out the issue with the filename /content-disposition… so feel free to pick a different URL to implement the content-disposition (I’ll see if I can find one somewhere also) but the example model was just a PDF I knew everyone could get to publicly to test.

1 Like

Incidentally I checked your caps remark and actually that did work so in fact the model does appear to work with that change… I will try mine with caps adjustment with Content-Disposition to make sure this was not the problem

1 Like

Hi @Charles

Got it…

Be careful when informing the header name, as it is case sensitive.

Please, change it to the correct value and let me know if it works

@Charles

If you want to see all response headers, you can:

1 - Insert a breakpoint in the Message Box activity (Press F9 or Right click > Toggle Breakpoint )

image

2 - Debug your project

image

3 - In the Watch panel, click on Add Watch

4 - Type Headers_Out and click on the icon

image

5 - You will be able to see all headers (response)

ok I will try this- also I have updated the model again but the request header still isn’t found although I can see it in the browser debugging.

So I have:

image

image

but still:

image

and in the request I can see the information just watching the browser network monitor:

image

1 Like

@Charles,

I’ll try to implement a workaround and if it works I’ll share this possible solution with you

but it’s weird because in the model I sent you which was a PDF get the Content-Length worked but in this which is similar even Content-Length returns “The given key was not present in the dictionary”

1 Like

Does it return other headers?

What status code does it return?

Will check debugging as you suggested because the HTTP response header Ive pasted above is the one from the actual button click. In the model I’m only sending the cookie value to keep the session I’ve already started in the browser in BG. However, since the Content-Length worked I’m thinking maybe my request is not fully formed with only a cookie header value and therefore the response back does not match 100% the browser action response header. Besides cookie any ideas what are the bare minimum request GET headers that might be needed to match the button click?

1 Like

Hi @Charles,

Here you a go a possible workaround:

1 - Access the portal and navigate to the page that you should perform that click. In this case, I’ll use UIPath Forum as example and “Download All” would be my button (in this step your automation should not click on the button):

2 - Open the Developer Tools (shortcut F12, use Send Hot Key activity)

3 - Navigate to Network (use Click activity)

4 - Click on Clear (use click activity)

5 - Finally, click on the URL that downloads the file and and immediately afterwards click on Stop recording network log (use click activity or Send Hot Key activity - shortcut: CTRL + E)

6 - Click on Download icon and save the file (use click activity)

7 - Use a Read Text File activity to read the file from step 6

8 - Use a Deserialize JSON activity

9 - Then, you just need to find your request (I believe the best way is to look for the url) and get the response header you want.

Try to implement this and let me know if it works

If it works and you agree, kindly mark this post as solution to close this topic.

If you need extra help and/or have any question, please let me know :slight_smile:

Thanks!

@Charles,

I think only sending the cookie it is not enough the get the expected response.

Without a documentation is difficult to describe how you should build your request to match the click request.

If this system was created by your company, you can talk to the developer or take a look at the source code if you have access

There is something else you can do… which is take a look at your request in the Developer Tools (Network). You just need to find the correct request and you will find all information about it. But, you’ll find a lot of information that you don’t need to put in the request you want to build.

ok thanks for the all the input here- it’s definitely helpful to know the Header_Output works in a simple model. Unfortunately this is not a formally documented API, just a complex web application front end so I’m left to manually trying to build out the sufficient request structure from scratch.

However with your pointers on debugging and the HTTP request object above I’ll spend some time trying to add one variable at a time and monitoring the responses to see if I can trigger the same response header value eventually!

1 Like

I’ll try and see if I can use the deserialize option above but the browser summary request info is:

Response Headers

Cache-Control: no-cache, no-store, must-revalidate
Content-Disposition: attachment; filename=michael_1231231231.pdf
Content-Length: 39062
Content-Type: application/pdf
Date: Mon, 28 Feb 2022 00:41:05 GMT
Digest: md5=tcCOpYfeabHKED9pRxZoaQ==
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/10.0
Strict-Transport-Security: max-age=15768000;includeSubDomains;preload
X-Content-Type-Options: nosniff
X-Correlation-Id: 6390ce68-6801-4b8a-940d-ca6403ab3487
X-XSS-Protection: 1; mode=block

Request Headers:

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Cookie: _fbp=fb.1.1645124166472.1109289752; __unam=83bb4f4-17f04909567-354b9642-3; s_fid=6A0F9D3FDEBBBF7A-03F5F8F655FF671A; s_nr=1645128072722-New; s_vnum=1646110800723%26vn%3D1; s_lv=1645128072725; s_ev36=%5B%5B%27Direct%27%2C%271645128072728%27%5D%5D; s_ev37=%5B%5B%27Direct%27%2C%271645128072728%27%5D%5D; _ga=GA1.2.1333290117.1645128073; __qca=P0-256837186-1645128300803; _pendo_accountId.bab997fe-1554-4e4a-6760-3afebac71371=26afacbe-0596-4384-8266-cca7d3773c88; _pendo_visitorId.bab997fe-1554-4e4a-6760-3afebac71371=770fedd6-571a-4db2-a921-07e6ce22c383; i18next=en-US; __RequestVerificationToken=vAicXBjGMKM8EXsY7a78NCAGGYoSytRaBS_IJDSOLcy3z2vx4_IuShWFW4rmyqtHRvTSHn0H_pUPsGg-mKB3fr4Mi1w1; .ASPXAUTH=61E4E02A45D1C91F56AD7F0FFE246AA14267B8E89692AF48DA08B080C8A9014CC065DBB29C5A7DF951F1B0EFB7671023E50646551F116AABF2A1FED0309A2819617E283D041B493442BCDF714B7CE056183B78DD2E2F8C4346CB6E46A0B728AAB3C1898D713CEE1CF45A8A03F390555D86EDB75464387BBA1A6AF4A70F967A834D13146905C6FEC4A6FEA9D3BD23FE4B6C2322F541615338E31DB16A8B96FD0DAC10E7C0; _pendo_meta.bab997fe-1554-4e4a-6760-3afebac71371=2801597026; _gid=GA1.2.807818444.1646008401
Host: recruiting.ultipro.com
Referer: https://site.com URL
sec-ch-ua: " Not A;Brand";v=“99”, “Chromium”;v=“98”, “Google Chrome”;v=“98”
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: “Windows”
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36

1 Like