Halting the callback chains

On this article I will share a technique to find out more about callbacks in Ruby on Rails framework.

Callbacks are a common way of implicitly invoking actions when an event fires inside a system. Many web frameworks like Rails or Laravel depend on this mechanism to handle esoteric events. A chain of callbacks is created when multiple callbacks are being fired one after another. Finally, we will call halting such a chain when we stop the event propagation.

Halting a callback in Rails is simple if we use the abstraction provided by the framework. Specifically, calling

throw :abort

will halt the ActiveRecord callbacks.

In larger Rails systems where legacy code or questionable techniques, like depending in implicit ActiveRecord callbacks for domain specific logic, may have been accumulated, halting and debugging callbacks is not a trivial task. One way to approach such troubleshooting is by learning more about the callbacks of our system. To do that we will use the pry debugger.

The class methods we are looking for is:

_#{action_name}_callbacks # e.g., _destroy_callbacks

Then using select, map and filter I am able to list and iterate over any callback given an ActiveModel class:

User._destroy_callbacks.select {|cb| cb.kind == :after }.map(&:filter)

=>
[
  :destroy_user_friends,
  :build_ast,
  :disconnect_from_bank_system,
  :check_soft_delete,
  ...
]

Caching in HTTP/1.1

Throughout my work experience with web applications HTTP caching was a must have element of the request-response system I was building. HTTP caching is a huge topic (e.g., this is the RFC for HTTP/1.1 – https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html), and in this post I want to discuss my experience with the cache directives and specifically the If-Match or If-None-Match ones.

The directives are unidirectional in HTTP/1.1. Let’s suppose we have a request response cycle. There is a simple web frontend rendered in a browser and the user has clicked a button. The first ever request will go to some server which will server an answer. Unidirectional means that even if the request contains some directive, that doesn’t provide any guarantee for the existence of such directive in the response. They may exist as is and they may not exist. Some common request directives include: no-cache, no-store, max-stale, min-fresh, no-transform, only-if-cached.  Some response ones are: public, must-revalidate, proxy-revalidate and others.

If we zoom into the If-Match directive we notice the close relation with the entity tags (or ETags). An ETag represents a resource and is a digest of information. Using such digest helps the client decide whether the resource returned in the response is stale or fresh. 

HTTP is a stateless protocol. ETags represent a state though. If a response tells us a story where a resource is partially or fully stale or fresh then this means there is a background story. This background story is the state of the resource we chose to include in the request response cycle by using entity tags.

One way to use ETags is by including one in the response headers. Then subsequent HTTP requests will use this information with the If-None-Match header to determine whether the data is stale. The server then will compute an information digest for the requested resource, an ETag and will respond with 304 if the resource is fresh. Alternatively, it will respond with a new tag.

Some web frameworks like ruby on rails abstract ETags away from the programmer. The essence is whether the resource is fresh or not. So Rails has a method called

stale?

which uses ETags behind the scenes. That method is used usually alongside the 

fresh_when

method as described in the docs https://guides.rubyonrails.org/caching_with_rails.html.

Example usage:

curl -i http://localhost:3000/posts/1 

Content-Length: 667 
Etag: "123123122132" 
Last-Modified: Wed, 12 Nov 2014 15:44:46 GMT 

And then:

curl -i -H 'If-None-Match: "123123122132"' http://localhost:3000/posts/1 

HTTP/1.1 304 Not Modified 
Etag: "123123122132" 
Last-Modified: Wed, 12 Nov 2014 15:44:46 GMT 

The advantage of the above is that we gain the time that would normally be spent rendering the response and the response body is empty.

Finally, there are some interesting challenges that come with using such a cache mechanism. First, the content is not cached between users. Building a caching mechanism to care for such case would need a more custom solution. Second, user specific content (so, most of it in big applications) is not handled correctly. Every user will see a different timeline, has different followers and different connection graphs. Using the above simple cache mechanism will always return stale data in those cases so we will avoid it. To solve the problem of caching a timeline we could work outside the application layer. Each user can have their first x items of their timeline cached in an edge Redis server for instance.

Malware System Calls

My motivation for writing this essay was a graduate project I built while studying security in Georgia Tech. An important part of the system is a program that relies on finite state automata to train deep learning models.

Each state is a system call. The following table lists the system calls I used for developing the Linux kernel modules.

In the first column there is the eax register value, followed by the system call name, source code and the ebx, ecx, edx register values. The register values are the arguments we need to pass into the system calls or in the case of hooking the system calls these register values must be read and passed along to the hook.

  • eax: 4, name: sys_write, ebx: unsigned int, ecx: const char *, edx: size_t
  • eax: 5, name: sys_open, ebx: const char *, ecx: int, edx: int
  • eax: 11, name: sys_execve, ebx: struct pt_regs
  • eax: 15, name: sys_chmod, ebx: const char *, ecx: mode_t
  • eax: 23, name: sys_setuid, ebx: uid_t
  • eax: 24, name: sys_getuid
  • eax: 33, name: sys_access, ebx: const char *, ecx: int

Character Orientations

In this article, I comment on Erich Fromm’s theory of personality, by describing two of his personality types.

The Receptive Type

The receptive type needs to be supported by external factors. Eventually, this type believes it will be rewarded by the world or other people for doing a well-planned work and following controlling rules.

For example, an individual may lack confidence in their own abilities and try to follow the accepting and optimistic path.

It’s important to notice that a receptive co-worker will usually work in harmony with the productive type, can be a fundamental building member of a team and can grow into the productive type.

The Productive Type

The productive personality type transforms negative feelings into energy. In detail, a negative feeling will be fully or partially acknowledged and then it will be channeled into productive work hours, by focusing on building and delivering meaningful products and relationships.

For example, a productive type will focus on delivering a project in time valuing reason more than rules.

This is often considered as a healthy approach to the workplace inevitable challenges and usually results in a simple description such as a “good” co-worker.

Outro

People tend to deal with life in general and workplace problems more specifically, by developing certain personalities.

The receptive type focuses on external rewards and may lack confidence while it is on the path to becoming a productive type.

On the other hand, the productive type will overgrow external factors, is influenced by internal motivations and can turn negativity into productive behavior.