Why Sketchup crashes when cancel Class: Sketchup::Http::Request

I use Class: Sketchup::Http::Request to make a request to my cloud. The request looks like this

req = Sketchup::Http::Request.new( Constants::SiteURL, Sketchup::Http::POST)
req.start do |req, response|

end

But when I call

req.cancel

Sketchup crashes and shows me the bug report form and then closes.
What can be the reason of such kind of behavior?

Check the official Issue Tracker on GitHub …

If you do not see an issue, please file a report with a reproducible code snippet.

My first thought is that your sample code is not using a persistent reference. Local references can go out of scope easily.


You might be interested in reading this issue …

https://github.com/SketchUp/api-issue-tracker/issues/110

1 Like

Where can I get an information about scope?
For example I try to cancel the request in set_upload_progress_callback method to see if it works.

req.set_upload_progress_callback do |current, total|
              req.cancel
end

But it crashes.
Is this a situation without persistent reference?

It makes no sense to put a cancel call inside a loop without some kind of conditional expression.
Basically the first time through the loop the request would get cancelled.

You are using a local reference, ie: req

Since I cannot see all of your code, I cannot say. Is the code within a method ?

A persistent reference is an instance variable (@req,) or a class/module variable (@@req.)

From any good Ruby programming book. There are free ones available for download. See

Thanks Dan, my code is within a class method

def self.setCallbacks
    @dialog.add_action_callback("Upload") { |action_context, value|
        req = Sketchup::Http::Request.new( Constants::SiteURL, Sketchup::Http::POST)

        req.set_upload_progress_callback do |current, total|
              req.cancel
        end
        
       req.start do |req, response|
       end

I think I have a req reference “alive” ?

Perhaps not. Local references inside methods go out of scope when the method returns (ends), and Ruby’s automatic garbage collection will destroy objects that are no longer referenced.

I am unsure if the callback’s block object will preserve the local req reference inside it.

So try something like …

def self.setCallbacks
  @dialog.add_action_callback("Upload") { |action_context, value|
    @req = Sketchup::Http::Request.new( Constants::SiteURL, Sketchup::Http::POST)

    # load the file text into a reference to a String object
    @req.body= @some_file_text

    @req.set_upload_progress_callback do |current, total|
      if @req.status == Sketchup::Http::STATUS_FAILED
        puts "Upload Failed"
        @req.cancel
      elsif @req.status == Sketchup::Http::STATUS_CANCELED
        puts "Upload Canceled"
      else
        puts total
        if @req.status == Sketchup::Http::STATUS_SUCCESS
          puts "Upload Successful"
        end
      end
    end

    @req.start
  }
end

I’ve tried to make req an instance field @req.
I also can see the value of @req.status it gets 2.
But after @req.cancel it again crashes.

@req.set_upload_progress_callback do |current, total|
                puts @req.status
                @req.cancel                  
end

Anyway thank you very much for help.

Once again, you cannot have @req.cancel inside a progress callback block without a condition on it. It makes no sense.

Did you fill out the BugSplat! form and send it in ? Crash report number ?


It may be due to the fact that this is nested inside a web dialog callback block.

I do NOT get a crash with this code …

module CrashTest

  extend self

  def set_callbacks

    @req = Sketchup::Http::Request.new( "http://localhost", Sketchup::Http::POST)
    
    @req.body = "Some fake text."

    @req.set_upload_progress_callback do |current, total|
      puts "Canceling ..."
      @req.cancel
    end

    @req.start do |request, response|
      puts "Starting ..."
    end

  end
  
  def go
    set_callbacks()
  end

end

… but then again I do not see the progress callback block having executed.
(Perhaps the fake text is too small?)

I know that it makes no sense but I think to solve the problem about the crash then add appropriate condition.I think it is not connected to the main problem.

Yes I have filled and sent it for several times, I also have mentioned an email address but I couldn’t find the report number(see the picture bellow)

I’ve moved the call of set_callbacks function out of the callback (immediately when I open the extension) but I could see the crash again.
I also examined that it crashes only during post requests, when the server also waits for the post request. In my case the controller action has [HttpPost] attribute, I use .Net so the main condition is there shouldn’t be any redirect I guess.
I also tried to post to this url. I know it also makes no sense, but in this situation I always get crash. please try this one to your end.

        def set_callbacks
           @req = Sketchup::Http::Request.new('https://www.microsoft.com/en-us/', Sketchup::Http::POST)
          
           @req.body = "Some fake text."
       
           @req.set_upload_progress_callback do |current, total|
             puts "Canceling ..."
             @req.cancel
             puts "after cancel"
           end
       
           @req.start do |request, response|
             puts "Starting ..."
             puts response.status_code 
           end

      end

About callback I have tried this code and could see the progress callback having executed

     def set_callbacks
           @req = Sketchup::Http::Request.new('http://localhost:1334/' + 'ClientDashboard/List', Sketchup::Http::GET) 
          
           @req.body = "Some fake text."
       
           @req.set_upload_progress_callback do |current, total|
             puts "Canceling ..."
             @req.cancel
             puts "after cancel"
           end
       
           @req.start do |request, response|
             puts "Starting ..."
             puts response.status_code 
           end

      end

and in ruby console I see

    Canceling ...
    Starting ...
    200
    after cancel

As you can see here I use Sketchup::Http::GET with @req.body = "Some fake text."
I don’t know whether this is correct or not, but it says that prrogress callback is executed.

Can you provide a complete example that reproduce the crash? We could then hook it up to the debugger and see what is going on.

Edit: If you do, please open an issue in the issue tracker: Issues · SketchUp/api-issue-tracker · GitHub

1 Like

Hi ThomThom,

here is the code to reproduce the bug (SU 24):

request = Sketchup::Http::Request.new('https://some_wrong_subdomain.modelur.com/', 'POST')
request.headers = { 'Content-Type' => 'application/json' }
request.body = ''

request.start do |_request, response|
  request.cancel
end

Can’t find it in API issue tracker, should I add it?

This weird because the start callback block is not supposed to get called until the response comes back.

If you look at the code snippet for the cancel method, you will see that the call is not within the start response block.


In the above reproducible snippets, the cancel is called from the upload progress callback block.

First of all, The SU Ruby API should not result in bug splats, regardless of how it’s used. It should always raise errors/exceptions.

I believe the Sketchup::Http objects were created (SU 2017) because the Ruby Net::HTTP library would block the SketchUp UI if a large request upload or response download was required.

What blocks in SU is different than what blocks in stand-alone Ruby. Regardless, Sketchup::Http is a very simple API that does not have many options, especially when compared to Ruby’s Net::HTTP.

So, if one wants full control of the http connection, Net::HTTP is probably a better choice, but it will block SU until the request/response are complete.

Two items come to mind with Sketchup::Http.

  1. It generates a keep-alive request, but there is no way to reuse the connection. I haven’t debugged things to determine whether it’s closing the socket properly.
  2. A request body has to be assembled before beginning the request. Many http clients allow an enumerable or ‘io’ like body, which means the full body doesn’t have to be assembled.